Re[31]: AdvancedHints Beta
От: Мизантроп  
Дата: 14.09.09 10:03
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Это уже сейчас есть, рефлекшн называется. Метакласс это тип.


Да, есть, но скорость работы ужасающа. А кроме того, не позволяет типизировать эту самую type. Впрочем, может быть я просто что-то неправильно делал? Может Вы продемонстрируете праваильный подход?

S>>>Тогда в эту "любую" функцию нельзя будет передать альтернативную порождающую функцию (которая, к примеру, возвращает закешированный экземпляр вместо нового).


Z>А вот если бы это была функция (нет ничего, что мешает ей стать таковой), то ей можно было бы манипулировать как функцией. Метакласс же сам по себе ничего не может, для него требуется инфраструктура.


А функция сама собой вызывается? Для работы с ней инфраструктуру создавать не требуется?
"Нормальные герои всегда идут в обход!"
Re[32]: AdvancedHints Beta
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.09.09 10:19
Оценка:
Здравствуйте, Мизантроп, Вы писали:
М>А я и не претендую на новизну. Но мне вот как-то не удалось найти ни одного внятного или хотя-бы полувнятного обоснования, чем она плоха. Похоже, чистый маркетинг, стремление максимальной похожести на Си.
Она плоха тем, что не нужна. Ничего фундаментально нового в язык она не привносит. Никакой "максимальной похожести на Си" в дотнете нету. И минимальной, кстати, тоже.

М>А зачем его чем-то заменять? Вы написали метод Consumer, принимающий параметром фабричную функцию, ну так и передавайте ему фабричную функцию, либо создающую новый экзэмпляр, либо берущий его из кэша. В чём проблема?

Ну вот и нет никакой проблемы. Буду передавать фабричную функцию. Где здесь место "метаклассу"? Зачем он нужен?
М>Нет, ну я похоже действительно что-то не понимаю, но в чём будет выигрыш, ради которого есть смысл смешивать здесь объектный и функциональный подход?
Как в чём? В универсальности подхода. Ты предлагаешь принимать в Consumer некий метакласс. Это, фактически, гвоздями прибивает единственную доступную реализацию. Для чего? Какой от этого бенефит? Фабричная функция, с учётом ковариантности делегатов, прекрасно покрывает сценарий "давайте передадим вместо конструктора Foo конструктор Bar: Foo.

М>Ну прячется, и что с того? Почти везде что-нибудь где-нибудь да прячется. Сохраняя метакласс с пятью конструкторами, мы можем далее вызывать по мере надобности любой из них.

А можно в студию пример сценария, где вот это вот будет хоть как-то полезно?
М> А сохранив делегат с конструктором, мы оказываемся жёстко привязаны к этому конструктору, и придётся хранить пять делегатов.
Прекрасно. Если потребителю нужно именно пять способов конструирования (что маловероятно, хотя я, в принципе, могу себе придумать экзотическое применение этой технике), то мы получаем классическое место для применения интерфейса. Т.е. у нас будет
IFooFactory
{
  Foo NewFoo(); // default constructor
  Foo NewFoo(SerializationInfo info, StreamingContext context); // serialization constructore
  Foo NewFoo(int a, int b); // constructor+initializer
}

То, что вы предлагаете — это встроенная в язык реализация этого паттерна. Она слишком редко востребована, и слишком легко может быть написана вручную. Поэтому её и не стали включаить в C#.

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

А мне вот непонятно стремление засунуть ООП куда надо и не надо. Там, где можно обойтись интерфейсом, а то и просто делегатом, зачем-то предлагается тяжелая артиллерия в виде классов-синглтонов.

М>А объект, о чьём конструировании мы ведём речь, есть порождение объектного подхода, а не функционального.Для него "чужеродна" как раз функциональщина, и применять её стоит там, где от этого будет действительно реальный выиграш, не достижимый в рамках объектного подхода.


Выигрыш был озвучен в самом начале этой дискуссии. Существующее неравноправие конструкторов и статик функций приводит к необходимости писать лишний код. И, в частности, не работает вывод типов генерик-аргументов. Метаклассы эту проблему никак не решат.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[33]: AdvancedHints Beta
От: Мизантроп  
Дата: 14.09.09 11:19
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Она плоха тем, что не нужна. Ничего фундаментально нового в язык она не привносит. Никакой "максимальной похожести на Си" в дотнете нету. И минимальной, кстати, тоже.


О том, что синтаксис C# максимально приближен к Си для того, чтобы облегчить переход на нег Си-программистов, я читал ещё в начале века в высказываниях представителя Microsoft. Извините, но искать ссылку не буду.

S>Как в чём? В универсальности подхода. Ты предлагаешь принимать в Consumer некий метакласс. Это, фактически, гвоздями прибивает единственную доступную реализацию. Для чего? Какой от этого бенефит? Фабричная функция, с учётом ковариантности делегатов, прекрасно покрывает сценарий "давайте передадим вместо конструктора Foo конструктор Bar: Foo.


Никакого прибивания. Если нужен фабричный метод, надо и писать фабричный метод. Почему обязательно противопоставлять? А если нужен класс, то никто не запрещает передать туда тип любого потомка. В том числе и дженерик-тип.

М>>Ну прячется, и что с того? Почти везде что-нибудь где-нибудь да прячется. Сохраняя метакласс с пятью конструкторами, мы можем далее вызывать по мере надобности любой из них.

S>А можно в студию пример сценария, где вот это вот будет хоть как-то полезно?
М>> А сохранив делегат с конструктором, мы оказываемся жёстко привязаны к этому конструктору, и придётся хранить пять делегатов.
S>Прекрасно. Если потребителю нужно именно пять способов конструирования (что маловероятно, хотя я, в принципе, могу себе придумать экзотическое применение этой технике), то мы получаем классическое место для применения интерфейса. Т.е. у нас будет
S>
S>IFooFactory
S>{
S>  Foo NewFoo(); // default constructor
S>  Foo NewFoo(SerializationInfo info, StreamingContext context); // serialization constructore
S>  Foo NewFoo(int a, int b); // constructor+initializer
S>}
S>

S>То, что вы предлагаете — это встроенная в язык реализация этого паттерна. Она слишком редко востребована, и слишком легко может быть написана вручную. Поэтому её и не стали включаить в C#.

S>А мне вот непонятно стремление засунуть ООП куда надо и не надо. Там, где можно обойтись интерфейсом, а то и просто делегатом, зачем-то предлагается тяжелая артиллерия в виде классов-синглтонов.


И класс, и делегат, и интерфейсы — всё это порождение ООП, это не альтернатива ООП, а как раз-таки его применение.

Мы начали ходить по кругу, а в Ваших высказываниях явно звучат нотки раздражения. Давайте лучше на этом завершим дискуссию, всё равно не похоже, что сможем прийти к какому-то общему знаменателю.
"Нормальные герои всегда идут в обход!"
Re[34]: AdvancedHints Beta
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.09.09 04:49
Оценка:
Здравствуйте, Мизантроп, Вы писали:
М>О том, что синтаксис C# максимально приближен к Си для того, чтобы облегчить переход на нег Си-программистов, я читал ещё в начале века в высказываниях представителя Microsoft. Извините, но искать ссылку не буду.
Ага. А еще он похож на джаву, чтобы облегчить переход джава-программистов. И на С++, в тех же целях. Ну, и, естественно, на JavaScript.

Дело в том, что это никакого отношения к вопросу не имеет. Семантика языка радикально отличается от C.

М>Никакого прибивания. Если нужен фабричный метод, надо и писать фабричный метод. Почему обязательно противопоставлять? А если нужен класс, то никто не запрещает передать туда тип любого потомка. В том числе и дженерик-тип.

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

М>Мы начали ходить по кругу, а в Ваших высказываниях явно звучат нотки раздражения. Давайте лучше на этом завершим дискуссию, всё равно не похоже, что сможем прийти к какому-то общему знаменателю.

... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[35]: AdvancedHints Beta
От: Мизантроп  
Дата: 15.09.09 11:14
Оценка:
Здравствуйте, Sinclair, Вы писали:

М>>Никакого прибивания. Если нужен фабричный метод, надо и писать фабричный метод. Почему обязательно противопоставлять? А если нужен класс, то никто не запрещает передать туда тип любого потомка. В том числе и дженерик-тип.

S>По-прежнему не вижу в этих рассуждениях ответа не простой вопрос про кэширование экземпляров. Ты, случайно, не виляешь?

Да нет, я просто не понимаю, что не так с кэшированием Ваш Customer ожидает фабричный делегат? Ну и на здоровье, передайте ему такой делегат, тем-же замыканием поместив в него ссылку на метакласс. И пусть этот делегат либо берёт объект из кэша, либо создаёт новый. И дженерик здесь вполне пройдет, причём для этого будет достаточно уже существующей механики. Что не так-то? Что, если будет возможность передавать конструктор, то данная ситуация будет разруливаться как-то иначе?

Сохранение такого делегата в поле? А если в поле сохранять метакласс, то чем будет хуже? Тем что придётся дополнительно писать слово из трёх букв? Зато получим доступ к метаклассу, например, к статическим членам именно этого класса. Пять конструкторов? Да их полно, объектов с множеством конструкторов. Простой пример на вскидку — создать сокетное соединение, приняв на входе либо либо имя хоста, либо IP в Int32, либо объект IPAddress. Да ещё при этом созлавать объект не того типа, который заложил разработчик фабрики, а того, который укажет пользователь этой фабрики.

Говорю-же, по кругу ходим.
"Нормальные герои всегда идут в обход!"
Re[36]: AdvancedHints Beta
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.09.09 11:59
Оценка:
Здравствуйте, Мизантроп, Вы писали:

М>Здравствуйте, Sinclair, Вы писали:


М>>>Никакого прибивания. Если нужен фабричный метод, надо и писать фабричный метод. Почему обязательно противопоставлять? А если нужен класс, то никто не запрещает передать туда тип любого потомка. В том числе и дженерик-тип.

S>>По-прежнему не вижу в этих рассуждениях ответа не простой вопрос про кэширование экземпляров. Ты, случайно, не виляешь?

М>Да нет, я просто не понимаю, что не так с кэшированием Ваш Customer ожидает фабричный делегат?

Поясняю еще раз, медленно: есть два варианта.
1. Наш кастомер ожидает фабричный делегат.
В этом варианте, зачем вообще приплетать какой-то метакласс? Зачем он вам сдался? Всё прекрасно работает безо всяких типизированных метаклассов. Можно подменить как тип создаваемого объекта (с проверкой совместимости в компайл-тайме), так и алгоритм порождения.
2. Наш кастомер ожидает метакласс.
Это, в принципе, логично. Если штатный способ конструировать объекты — это метакласс, то разработчик именно метакласс и будет ожидать. Это не ему нужно уметь брать объекты из кэша; его задача — абстрагироваться от источника объектов (иначе бы он сам сделал у себя new).
В этом случае применить кэширование интегратору такого консумера уже не удастся.

М> Ну и на здоровье, передайте ему такой делегат, тем-же замыканием поместив в него ссылку на метакласс. И пусть этот делегат либо берёт объект из кэша, либо создаёт новый. И дженерик здесь вполне пройдет, причём для этого будет достаточно уже существующей механики. Что не так-то? Что, если будет возможность передавать конструктор, то данная ситуация будет разруливаться как-то иначе?

Конечно. Не будет в принципе этого выбора — что принимать. Вы вообще отдаёте себе отчёт, что ваше предложение эквивалентно заставлению разработчика любого потребителя фабрики думать — пользоваться ли "стандартным" способом, и ограничивать гибкость, или "нестандартным", и заставлять делать замыкания даже в тривиальном случае?

Зачем вы это изобретаете? Есть еще много способов усложнить язык. Давайте их все тогда обсудим.

М>Сохранение такого делегата в поле? А если в поле сохранять метакласс, то чем будет хуже?

Тем, что от метакласса нельзя отнаследоваться. Нельзя придумать "свой" метакласс для генерации IP соединений.

М> Тем что придётся дополнительно писать слово из трёх букв? Зато получим доступ к метаклассу, например, к статическим членам именно этого класса.

ОК, отлично. Добро пожаловать, статические виртуальные члены. Давненько я вас не видел. Итак, мы уже получили два механизма виртуальности — "обычный", работающий на уровне экземпляра, и "волшебный" — работающий на уровне класса. Вы же именно это подразумеваете, правильно? Чтобы можно было делать
public class Foo
{
  public static virtual int ClassId{ get {return 1;}}
}
public class Bar: Foo
{
  public static override int ClassId{ get {return 2;}}
}

Ведь без виртуальности никакого "к статическим членам именно этого класса" смысла не имеет. В существующей реальности Bar.ClassId будет ровно тем же Foo.ClassId, поэтому никакой метакласс ничего другого вам не отдаст.
Прекрасно, осталось понять — есть ли полезный сценарий для этого счастья, который не покрывается существуюшими механизмами.

М>Пять конструкторов? Да их полно, объектов с множеством конструкторов. Простой пример на вскидку — создать сокетное соединение, приняв на входе либо либо имя хоста, либо IP в Int32, либо объект IPAddress. Да ещё при этом созлавать объект не того типа, который заложил разработчик фабрики, а того, который укажет пользователь этой фабрики.

Да ну. Никому это не нужно. У нас что, какое-то богатое дерево наследников у сокета? Какую именно задачу будет решать метакласс сокета в таком приложении?

М>Говорю-же, по кругу ходим.

Это вы зачем-то упорно ходите по кругу. Поймите, я все эти идеи про метаклассы передумал больше пяти лет назад, когда еще вовсю писал на дельфи. Сначала казалось странным, что такая удобная штука отсутствует. А потом оказалось, что она, в общем-то, без нужды.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[37]: AdvancedHints Beta
От: Мизантроп  
Дата: 15.09.09 14:21
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Да ну. Никому это не нужно. У нас что, какое-то богатое дерево наследников у сокета? Какую именно задачу будет решать метакласс сокета в таком приложении?


Метакласс сокета — никакую. Но он может быть частью объекта, представляющего соединения. И вот этот объект может обладать тем функционалом, каким его наполнит пользователь фабрики. То есть роль фабрики может выполнять некий менеджер, обеспечивающий функционирование транспортного уровня, оптимизируя доступ к ресурссам всех объектов-соединений.. А прикладной уровень определяет пользователь менеджера, путём написания потомков и указания менеджеру их класса. Да-да, согласен, то-же самое можно получить и другими средствами, например определением фабричного делегата.

Ну это так, на вскидку.

То есть Вы говорите, что это никому не нужно, а кэширование объектов, надо понимать, — вещь чрезвычайно востребованная программёрской общественностью, и каждому чуть ли не ежедневно приходится это делать. Видимо, Вы обладаете результатами каких-то широких статистических исследований на этот счёт, но у меня таких результов нет, потому возражать не буду. А кстати, а зачем в NET вообще кэшировать объекты? Собственно создание объекта происходит очень быстро, замечательно быстро. А раз мы запросили новый объект, то видимо намерены его инициализировать новыми данными. Тогда что мы выигрываем от кэширования? По-моему, так можно скорее создать дополнительные трудности сборщику мусара, чем получить прирост производительности. Я тут как-то проверял — оказалось, что просто создать объект заметно быстрее, чем лезть за ним в кэш. А если в условиях многопоточности, то и намного быстрее. А чем быстрее мы его "сбросим", тем проще будет сборщику — поправьте, пожалуйста, если я не прав.

S>Сначала казалось странным, что такая удобная штука отсутствует. А потом оказалось, что она, в общем-то, без нужды.


Если коротко подвести итог, то вывод таков — метакласс не нужен потому, что он не даст ничего такого, чего нельзя было-бы получить иными средствами. Я правильно понял?
"Нормальные герои всегда идут в обход!"
Re[38]: AdvancedHints Beta
От: Sinclair Россия https://github.com/evilguest/
Дата: 16.09.09 02:15
Оценка: +1
Здравствуйте, Мизантроп, Вы писали:


М>Метакласс сокета — никакую. Но он может быть частью объекта, представляющего соединения. И вот этот объект может обладать тем функционалом, каким его наполнит пользователь фабрики. То есть роль фабрики может выполнять некий менеджер, обеспечивающий функционирование транспортного уровня, оптимизируя доступ к ресурссам всех объектов-соединений.. А прикладной уровень определяет пользователь менеджера, путём написания потомков и указания менеджеру их класса. Да-да, согласен, то-же самое можно получить и другими средствами, например определением фабричного делегата.

Конечно. Я не вижу места построению целого отдельного класса там, где можно обойтись
а) делегатом на существующий метод — 0 строк
б) замыканием типа (address) => new Socket(address); — 1 строка
в) замыканием более сложной природы — 3 строки.
Это так, навскидку. А вы еще и предлагаете помимо метакласса нарулить какой-то отдельный класс-менеджер. Вам что, ресурсы некуда деть?

М>То есть Вы говорите, что это никому не нужно, а кэширование объектов, надо понимать, — вещь чрезвычайно востребованная программёрской общественностью, и каждому чуть ли не ежедневно приходится это делать. Видимо, Вы обладаете результатами каких-то широких статистических исследований на этот счёт, но у меня таких результов нет, потому возражать не буду. А кстати, а зачем в NET вообще кэшировать объекты? Собственно создание объекта происходит очень быстро, замечательно быстро. А раз мы запросили новый объект, то видимо намерены его инициализировать новыми данными. Тогда что мы выигрываем от кэширования?

М>По-моему, так можно скорее создать дополнительные трудности сборщику мусара, чем получить прирост производительности.
М>Я тут как-то проверял — оказалось, что просто создать объект заметно быстрее, чем лезть за ним в кэш. А если в условиях многопоточности, то и намного быстрее. А чем быстрее мы его "сбросим", тем проще будет сборщику — поправьте, пожалуйста, если я не прав.
1. Создание объекта может быть дешёвым, а инициализация — дорогой. Если я делаю объект "число фибоначчи", которое конструируется по его номеру, то мне очень выгодно возвращать готовое число в случае его наличия.
2. Добро пожаловать в мир Resource Pools. Подключения к базе данных, потоки, и прочие системные объекты, весьма дороги в создании с нуля. Их кэширование — крайне выгодно.
3. Дело даже не в этом. Кэширование — только один из примеров, когда стратегия порождения объекта может отличаться от вызова конструктора. Вы предлагаете встроить в язык ровно один способ подмены конструирования объекта. Ваша фабрика, реализованная метаклассом, будет уметь только подменять new Base(int a) на new Derived(int a).
Это слишком узкое решение. Выигрыш от него крайне мал, а затраты — велики.
Фабрика, реализованная делегатом, будет уметь не только то, что ваша, а еще и бесчисленное множество других трюков. При этом стоить она будет гораздо меньше.

М>Если коротко подвести итог, то вывод таков — метакласс не нужен потому, что он не даст ничего такого, чего нельзя было-бы получить иными средствами. Я правильно понял?

Примерно так. Вы приводите примеры сценариев, где использование метакласса менее удобно, чем любая альтернатива.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[39]: AdvancedHints Beta
От: Мизантроп  
Дата: 16.09.09 10:30
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Примерно так. Вы приводите примеры сценариев, где использование метакласса менее удобно, чем любая альтернатива.


Ну я так и понял — чисто субъективная причина. Но говоря подобнык вещи, не помешает уточнять: "мне менее удобно". Не стоит расписываться сразу за всё человечество, право, не стоит. Меня Вы не убедили. Впрочем, очень даже вероятно, что причиной тому — отсутствие у меня опыта в NET. Поживём — увидим.
"Нормальные герои всегда идут в обход!"
Re[40]: AdvancedHints Beta
От: Sinclair Россия https://github.com/evilguest/
Дата: 16.09.09 10:56
Оценка: +1
Здравствуйте, Мизантроп, Вы писали:
М>Ну я так и понял — чисто субъективная причина.
Нет. Когда мы говорим об удобстве разработки есть ровно одна объективная метрика: количество строк кода, которые нужно написать.
Поэтому любой подход, построенный на том, что "а вот тут мы порождаем простенький класс с тремя полями" сразу пролетает по сравнению "а вот тут мы просто присваиваем свойству делегат".
Любой подход, который требует "а вот тут нам надо заранее решить, будет ли у потомков возможность хоть что-то изменить", тоже сразу пролетает — потому что замена недофабрики-метакласса на настоящую фабрику требует переделки потребителя фабрики. Опять увеличивая количество строк кода.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[38]: AdvancedHints Beta
От: VladD2 Российская Империя www.nemerle.org
Дата: 16.09.09 14:00
Оценка:
Здравствуйте, Мизантроп, Вы писали:

М>Если коротко подвести итог, то вывод таков — метакласс не нужен потому, что он не даст ничего такого, чего нельзя было-бы получить иными средствами. Я правильно понял?


... иными, более простыми методами.
Не ты ли говорил о том, что не надо создавать сущностей без необходимости? Так кто же из нас предлагает идти против "бритвы Оками"?

Давай еще раз. Трактовка конструкторов как статических методов порождающих объекты дает:
1. Возможность прозрачного вывода типов для конструкторов в C# и VB.
2. Возможность применять к конструкторам те же правила, что и к обычным функциям. Это в свою очередь позволяет упростить описание языка (т.е. сам язык) и упростить компилятор. Это, так же, позволяет легко передавать конструкторы куда нам нужно и хранить их где нам нужно.

Ты же предлагаешь, грубо говоря, воплотить в языке паттерн "Фабрика классов". Которые конечно тоже лучше чем ничего, но тем не менее сложнее и не дает нам преимуществ описанных в пункте 1.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.