Re[14]: Утиные истории vs ООП?
От: Павел Кузнецов  
Дата: 14.10.05 17:10
Оценка:
AndrewVK,

> E> Если duck typing встраивается в статически типизированный язык, то получаем те же самые проверки.

>
> Нет, не получаем, потому что нет формального контракта, связанного с сигнатурой. Совпадение сигнатуры еще ничего не означает. А если мы такой формальный контракт введем, то получим интерфейсы — вид сбоку.

Если речь идет о concepts, то совсем не интерфейсы в смысле C++/C#/Java: указать, что данный тип удовлетворяет заданным ограничениям можно при использовании типа, а не при его определении.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[23]: Утиные истории vs ООП?
От: Павел Кузнецов  
Дата: 14.10.05 17:13
Оценка: +1
eao197,

> AVK>Т.е. то, что реальный софт пишут команды, ты в своей оценке не учитываешь?

>
> Блин, да я же не агитирую всех за тотальное использование duck typing-а. Я хочу понять границы его применимости.
> Командная разработка, действительно, вряд ли выиграет от использования duck typing-а. Это очень серьезный минус для duck typing-а.

Зависит от конкретной команды и конкретной задачи. Structural/Latent/Duck typing -- инструмент, вполне полезный и при командной разработке. Использование Smalltalk, Lisp и шаблонов C++ вполне это подтверждает.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[15]: Утиные истории vs ООП?
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 14.10.05 18:43
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

>> Нет, не получаем, потому что нет формального контракта, связанного с сигнатурой. Совпадение сигнатуры еще ничего не означает. А если мы такой формальный контракт введем, то получим интерфейсы — вид сбоку.


ПК>Если речь идет о concepts, то совсем не интерфейсы в смысле C++/C#/Java: указать, что данный тип удовлетворяет заданным ограничениям можно при использовании типа, а не при его определении.


А казалось бы, при чем тут С++?

Нет, речь не о concepts
... << RSDN@Home 1.2.0 alpha rev. 615 on Windows XP 5.1.2600.131072>>
AVK Blog
Re[24]: Утиные истории vs ООП?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 14.10.05 21:03
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

>> AVK>Т.е. то, что реальный софт пишут команды, ты в своей оценке не учитываешь?

>>
>> Блин, да я же не агитирую всех за тотальное использование duck typing-а. Я хочу понять границы его применимости.
>> Командная разработка, действительно, вряд ли выиграет от использования duck typing-а. Это очень серьезный минус для duck typing-а.

ПК>Зависит от конкретной команды и конкретной задачи. Structural/Latent/Duck typing -- инструмент, вполне полезный и при командной разработке. Использование Smalltalk, Lisp и шаблонов C++ вполне это подтверждает.


Согласен. Но здесь мы с AndrewVK говорили, как мне кажется, о среднестатистических командах.

Кстати, о конкретных командах и конкретных задачах подтвердает и то, что многие проекты на этих языках делаются очень небольшими, сплоченными коллективами, или вообще одиночками.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[6]: Утиные истории vs ООП?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.10.05 01:40
Оценка:
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>здесь возникает философский вопрос: а кто должен знать нужный способ? Мне (пока) наиболее изящным и, скажем так, прямым решением кажется концепция traits:

ЗХ>
ЗХ>traits< stream >.move_forward(stream, bytes);
ЗХ>


ЗХ>Здесь и интерфейс stream не раздувается, но и решение принимается "тем, кто знает как решать".

ЗХ>Грубо говоря, если появится еще один тип потока (предположенный мной), у которого есть функция seek, но смысл ее другой, а сдвигаться вперед надо функцией move — то нужно всего лишь описать traits для типа этого потока, не меняя клиентский код.


А может проще дать пользователю библиотеки просто функцию передать в качестве параметра? Будет в принципе тот же traits:
void load_header_and_data(Stream stream, Func<Stream, long, void> skip_data)
{
    h = load_header(stream);
    skip_data(stream, h.Length());
    load_data(stream);
}

и никаких расширений языка не потребуется.
В общем, если интерфейс заранее известен, то просто ползуемся ООП. Если нет, то применяем функциональный подход. В итоге все красиво, быстро и без утиных историй.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[10]: Утиные истории vs ООП?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.10.05 01:40
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>ОК. У каждой команды свое.


И у кого-то в него входит ничего не делающий код как в той ссылке о которой речь?
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Утиные истории vs ООП?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.10.05 01:40
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А вот как это могло бы работать в гипотетическом шарпе4:

S>
S>public class DuckDuckUser<T>
S>where T: duck IDuck
S>{
S>  public static MakeQuack(Duck duck)
S>    {
S>    duck.Quack();
S>    }
S>}
S>


Было бы куда интереснее если можно было бы просто декларативно описать мапинг между интерфейсами. Ну, что-то типа прокси, но декларитвно.

А пока можно сделать нечто вороде этого:
IProxyFactory factory = SomeFramewirk.DinnamicItfMaper.Map(specification);
...
INeeded itf = (INeeded)factory.CteateProxy(someObjRef);
...
itf.SomeCall(x, y, z);

Где specification — это описание мапинга тем или иным образом. Например, ХМЛ-файл следующего вида:
<Mapping From="SomeNS.SomeUnknownType" To="INeeded">
    <Method Name="SomeCallWithSomeName" To="SomeCall">
</Mapping>
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[19]: Утиные истории vs ООП?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.10.05 01:40
Оценка: 1 (1)
Здравствуйте, eao197, Вы писали:

E>Совсем не точка. Мы с AndrewVK говорили об объектах, которые поддерживают несколько интерфейсов. В частности, чемодан поддерживает: "контейнер для ручной клади", "хранилище хлама", "подставка". Речь шла о том, что если чемодан как подставку использовать для не подходящей вещи, то он сломается, а мы поимеем проблемы. На что я возразил, что интерфейс "подставка", реализованный СтекляннымЖурнальнымСтоликом для того же самого телефизора так же не подойдет, получится исключения. Поэтому все compile-time проверки в этом случае идут лесом.


Прекратите аналогии с реальным миром. Ну, право же демагогия да и только.

Понимаш ли. С нормальными интерфейсами есть две проблемы. Одна психологическая. Другая структураная (сажем так).

Структурная вызвана тем, что иногда бывает, так что объект ссылку на который нужно передать в некий метод неудается туда передать в виду того, что его разработчик не предусмотрел у него нужный интерфейс. Скорее всего нужный интерфейс есть, но его проектировшик видел его несколько иначе нежели чем ользователь. Так же бывает, когда два проектировщика создали два, возможно даже одинаковых, интерфейса предназначенных для одного и того же. Если все это дело происходит в рамках одного проекта (а это очень частая ситауция, так как промышленные библиотеки и фрэймворки обычно проектируются тщательнее и раньше, а как раз "свои" более безолаберно), то можно просто сделать рефакторинг устраня тем самым откровенный косяк в проектировании. Целью рефакторинга будет удаление одно из интерфейсов и замена его на второй. Если же объкт все же находится в чужой бибилиотеке, то можно воспользваться одним из паттернов проектирования (не даром они для ООП и разрабатывались) и создать, к примеру, объект-обертку хранящую в себе ссылку на нужный объект и преобразующую его интерфейс в требуемый для фунции.

Психологическая связана с тем, что все эти рефакторинги и создание оберток геморойны, а обертки еще и скорость могут понизить. Причем забавно, что многих как раз рефакторин не так пугает, как гипотетические тормоза.

Так вот, боязнь рефакторинга при наличии средств вроде IDEA/ReSharper/VS2005 — это просто от серости и лени. Выигрыш тут несравнимо больший чем затрачиваемые усилия. Заключается он в грамотном дизайне приложения. А это, в свою очередь, дает простоту отладки и развития проекта.

С производительностью хуже. Но тут есть два "но". Превое — это то что она по большому счету должна решаться улучшеием компилятора. Так лишние объекты и виртуальные вызовы методов локальных объектов (объектов которые используются только в локалном контексте, например, в одном стэкфрэйме или ссылка на которые находится только в одной переменной и можно вычислить, что эта перменная не меняется в процессе работы приложения) могут попросту устраняться оптимизирующими компиляторами. У джита и преджита есть все шансы определить локальность перменных. Второе — только в довольно редких местах такие промежуточные объекты (и другие решения на базе паттернов проектирования) ощутимо влияют на производительность прилоежния. Их можно отловить с помощью профайлера и уже на конечных этапах разрабокти переписать оптимально журтувя при этом качеством кода. Зато общий дизайн приложения будет куда лучше.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: Утиные истории vs ООП?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.10.05 01:40
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Если речь идет о concepts, то совсем не интерфейсы в смысле C++/C#/Java: указать, что данный тип удовлетворяет заданным ограничениям можно при использовании типа, а не при его определении.


Паш, concepts вводятся в С++ (если конечно вводятся), чтобы уменьшить последствия утиной типизации присутствующей в шаблонах сегодня. Причем средство это не обязательное, и когда все осознают его необходимость баАальшой вопрос.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[15]: Утиные истории vs ООП?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.10.05 01:40
Оценка:
Здравствуйте, eao197, Вы писали:

E>Так я, вроде, уже давно обозначил позицию: Re[4]: Утиные истории vs ООП?
Автор: eao197
Дата: 07.10.05

E>

E>ООП базируется на трех китах: инкапсуляция, наследование и полиморфизм.


От именно. И добиваясь полиморфности так где не надо ты ломашь не только принцип наследования, но и инкапсуляции, так как допускаешь обращение к данным в обход контракта класса.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[6]: Утиные истории vs ООП?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.10.05 01:52
Оценка: :)
Здравствуйте, Зверёк Харьковский, Вы писали:

ЗХ>Чтобы не хватался — надо сказать

ЗХ>
ЗХ>if(нечто can взять-за-ручку && нечто can унести) ...
ЗХ>

ЗХ>В этом случае от унесения не застрахован любой предмет с ручкой В том числе — дверь, если плохо прикреплена

Однако очень Русский по духу подход. Тянем все что похо лежит.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Утиные истории vs ООП?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.10.05 02:22
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:


>> Исторически статическая типизаия использовалась как способ дать компилятору подскази для построения эффективного кода. Например, С++ компилятор, строит vtbl для класса размером не на все возможные (в системе) сообщения, а только на определенные в этом классе. В Smalltalk, например, такой оптимизации не делается. По этому если Smalltalk объект получает "непонятное" для него сообщение, то он кидает исключение, а C++ объект начинает вести себя непредсказуемым образом (что почти всегда приводит к GPF, а иногда к порче данных или странному поведению).


ПК>Можно пояснить мысль поподробнее относительно того, что ты понимаешь под передачей объекту C++ "непонятного" для него сообщения?


Наверно нечто вроде:
int i = 0;
double* pd = (double*)&i;
*pd = 1.3;
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Утиные истории vs ООП?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.10.05 02:22
Оценка:
Здравствуйте, eao197, Вы писали:


E>А вот если мы начинаем адаптироваться к типам:

E>
E>def get_voice( beast )
E>    voice( beast )
E>end

E>class Duck; def crack; ... end; end;
E>class Dog; def gaff; ... end; end;

E>def voice( beast )
E>    if beast.respond_to( "crack" )
E>        beast.crack()
E>    elfif beast.respond_to( "gaff" )
E>        beast.gaff()
E>    end
E>end
E>

E>то это уже duck typing и есть. Этим то он от других форм полиморфизма и обобщенного программирования отличается. ИМХО.

Не, это уже процедурное программирование на котором эмулируется ООП. Закат солнца вручную.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Утиные истории vs ООП?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.10.05 02:22
Оценка:
Здравствуйте, AndrewVK, Вы писали:

AVK>В С# 3.0 duck typing в нескольких местах есть. Например сокращенная инициализация массива:

AVK>
AVK>IList<Bird> birds = new List<Bird> {penguin, eagle, hedgehog};
AVK>


AVK>Преобразуется компилятором в код:

AVK>
AVK>List<Bird> l = new List<Bird>();
AVK>l.Add(penguin);
AVK>l.Add(eagle);
AVK>l.Add(hedgehog);
AVK>IList<Bird> birds = l;
AVK>


AVK>Так вот, метод Add подцепляется через тот самый duck typing. Почему так? Очень просто. С одной стороны нельзя привязываться к конкретным существующим интерфейсам, потому что фича сверхуниверсальная, с другой нельзя вводить свой, потому что тогда существующие коллекции не будут работать, с третьей стороны необходимо поддержать extension methods, которые принципиально не могут реализовывать интерфейсы. Но это мера вынужденная, а не некий универсальный принцип.


Серьезно? А мужики то и не знают поди. Я вот тоже попробовал написать вот так:
using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        A a = new A { 1, 2, 3 };
    }
}

class A
{
    public void Add(int item)
    {
        Console.WriteLine(item);
    }
}

И мне рассказали, что:
Program.cs(8,20): error CS1801: The member initializer does not have an identifiable name
CSC : fatal error CS0001: Internal compiler error (0x80004005)
Program.cs(8,23): error CS1801: The member initializer does not have an identifiable name
CSC : fatal error CS0001: Internal compiler error (0x80004005)
Done building project "LINQConsoleApplication1.csproj" -- FAILED.
========== Build: 0 succeeded or up-to-date, 1 failed, 0 skipped ==========

А вот когда интерфейсик ICollection<int> реализовал:
using System;
using System.Collections.Generic;

class Program
{
    static void Main(string[] args)
    {
        A a = new A { 1, 2, 3 };
    }
}

class A : ICollection<int>
{
    #region ICollection<int> Members

    public void Add(int item)
    {
        Console.WriteLine(item);
    }

    public void Clear()
    {
        throw new Exception("The method or operation is not implemented.");
    }

    public bool Contains(int item)
    {
        throw new Exception("The method or operation is not implemented.");
    }

    public void CopyTo(int[] array, int arrayIndex)
    {
        throw new Exception("The method or operation is not implemented.");
    }

    public int Count
    {
        get { throw new Exception("The method or operation is not implemented."); }
    }

    public bool IsReadOnly
    {
        get { throw new Exception("The method or operation is not implemented."); }
    }

    public bool Remove(int item)
    {
        throw new Exception("The method or operation is not implemented.");
    }

    #endregion

    #region IEnumerable<int> Members

    public IEnumerator<int> GetEnumerator()
    {
        throw new Exception("The method or operation is not implemented.");
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        throw new Exception("The method or operation is not implemented.");
    }

    #endregion
}

...то сразу дали:
1
2
3


Доктор! Что я делаю не так?

Короче, слава богу такой фигни как утиные истории в шарпе все же стараются избегать.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Утиные истории vs ООП?
От: VladD2 Российская Империя www.nemerle.org
Дата: 15.10.05 02:29
Оценка: :)
Здравствуйте, VladD2, Вы писали:

Хм. Но вызывают то гады действительно по имени. Если сделать реализацию метода Add явно:
void ICollection<int>.Add(int item)
{
    Console.WriteLine(item);
}

...то компилятор выдал ошибку:
Program.cs(8,15): error CS0117: 'A' does not contain a definition for 'Add'
Program.cs(8,15): error CS0117: 'A' does not contain a definition for 'Add'
Program.cs(8,15): error CS0117: 'A' does not contain a definition for 'Add'
Done building project "LINQConsoleApplication1.csproj" -- FAILED.
========== Build: 0 succeeded or up-to-date, 1 failed, 0 skipped ==========


В общем, явно сырая альфа. И не туда, и не сюда. Без интерфйса жить не хотя, но интерфейс тоже не понимют.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: ICollection<T>.Add(T)
От: Belsen  
Дата: 15.10.05 04:39
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Хм. Но вызывают то гады действительно по имени. Если сделать реализацию метода Add явно:

VD>
VD>void ICollection<int>.Add(int item)
VD>{
VD>    Console.WriteLine(item);
VD>}
VD>

VD>...то компилятор выдал ошибку:

Возможно, это и правильно, что конструктор колекции требует публичного метода Add реализующего ICollection<T>.Add(T).
Если метод ICollection<T>.Add(T) скрыт, велика вероятность того, что колекция не допускает модификации.
Если бы привязка шла к явной реализации интерфейса, результат выполнения
var carvedinstone = new ReadOnlyCollection { 1, 2, 3 };

был бы далек от интуитивно ожидаемого.
I might be wrong...
Re[7]: Утиные истории vs ООП?
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 15.10.05 07:16
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>А может проще дать пользователю библиотеки просто функцию передать в качестве параметра? Будет в принципе тот же traits:

VD>
VD>void load_header_and_data(Stream stream, Func<Stream, long, void> skip_data)
VD>{
VD>    h = load_header(stream);
VD>    skip_data(stream, h.Length());
VD>    load_data(stream);
VD>}
VD>

VD>и никаких расширений языка не потребуется.

Нет, в этом случае пользователю load_header_and_data нужно знать о том, что внутри используется skip_data. А от этого пользователя load_header_and_data хотелось бы избавить -- это не его проблемы. Так что вариант с утиными историями или traits-ами гораздо удобнее.
... << RSDN@Home 1.1.4 stable rev. 510>>


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[8]: Утиные истории vs ООП?
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.10.05 01:00
Оценка:
Здравствуйте, eao197, Вы писали:

E>Нет, в этом случае пользователю load_header_and_data нужно знать о том, что внутри используется skip_data. А от этого пользователя load_header_and_data хотелось бы избавить -- это не его проблемы. Так что вариант с утиными историями или traits-ами гораздо удобнее.


Ему и так нужно знать. Только тут хотя бы он может задать то что хочет, а не полагаться на соотвествие имен.
... << RSDN@Home 1.2.0 alpha rev. 618>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: Утиные истории vs ООП?
От: Павел Кузнецов  
Дата: 17.10.05 18:19
Оценка:
VladD2,

> ПК> ОК. У каждой команды свое.

>
> И у кого-то в него входит ничего не делающий код как в той ссылке о которой речь?

Код по ссылке
Автор: eao197
Дата: 08.10.05
не "ничего не делает", а проверяет соответствие аргументов шаблона некоторым требованиям. И да, такой код вполне согласуется с понятиями хорошего стиля более, чем у одной команды. Для меня лично польза правил, запрещающих писать код, помогающий отлавливать ошибки на более ранних стадиях, весьма сомнительна.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[25]: Утиные истории vs ООП?
От: Павел Кузнецов  
Дата: 17.10.05 18:22
Оценка:
eao197,

> ПК> Зависит от конкретной команды и конкретной задачи. Structural/Latent/Duck typing -- инструмент, вполне полезный и при командной разработке. Использование Smalltalk, Lisp и шаблонов C++ вполне это подтверждает.


> Согласен. Но здесь мы с AndrewVK говорили, как мне кажется, о среднестатистических командах.


Средняя температура по больнице?

> Кстати, о конкретных командах и конкретных задачах подтвердает и то, что многие проекты на этих языках делаются очень небольшими, сплоченными коллективами, или вообще одиночками.


Имхо, очень по-разному... Во всяком случае, применительно к Си++ уж точно. О Smalltalk, Python, Ruby, Lisp etc. мне говорить сложно: в командной работе на этих языках я не участвовал.
Posted via RSDN NNTP Server 2.0 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.