Информация об изменениях

Сообщение Re[13]: Junk in — junk out от 22.03.2017 0:00

Изменено 22.03.2017 0:00 vdimas

Re[13]: Junk in — junk out
Здравствуйте, Qbit86, Вы писали:

Q>Почему этот алгоритм будет работать для reference-типов и не будет для value-типов, или наоборот?


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


Q>Если алгоритму передают некорректный экземпляр value-типа, то алгоритм поведёт себя так же, как если бы ему подали по не-null ссылке некорректный экземпляр reference-типа.


Не туда ты опять смотришь.
Я могу в прикладном виде описать гарантии, которые не дадут мне привести ref-объект в невалидное состояние.
Для value-типов ср-в обеспечения таких гарантий нет.
Однакое, есть сценарии, когда такие гарантии "почти есть".
Например — value-тип являться приватным полем ref-типа и инициализируется в конструкторе.
Помимо этого у обрабатывающих ф-ий стоит модификатор ref в аргументах, что тоже уменьшает вероятность "просто случайно подать".
Помимо этого такие структуры у меня НЕ реализуют известные библиотекам фреймворка интерфейсы, чтобы, опять же, защититься на уровне системы типов от "случайно не туда подали через неявный боксинг".
И т.д. и т.п.
Т.е. я насобирал много правил, помогающих уменьшать вероятность ошибок при проектировании в value-типах, но не смог найти 100% работающей защиты от неправильного использования, т.е. не смог поручить контроль за правильностью использования компилятору. Т.е. только ручками подобную корректность обеспечиваем в любом случае.


Q>Алгоритму могут передать объект значимого типа, который бросит `System.InvalidOperationException` в методе `GetEnumerator()`.


Исключения "not implemented" или "invalid operation" — это первые признаки плохой архитектуры.

Простой пример. Вот есть класс TcpClient.

У него 80% методов выбрасывают "invalid operation".
Почему? Потому что для этого типа оставили пустой конструктор и еще несколько "глупых" конструкторов.
В итоге, объект может находиться в невалидном (неинициализированном) состоянии.
Если убрать пустой конструктор, то у нас пропадает надобность в св-ве Active, а так же уходят все места в его внутреннем коде, которые проверяют это св-во.

В классе TcpClient необходимо было оставить только конструктор от аргументов host+port, а так же добавить конструктор от Socket.
В случае конструирования от Socket можно проверить инвариант сразу, проверив RemoteEndPoint или Connected, т.е. запретить конструировать объект TcpClient в невалидном состоянии.

На самом деле класс TcpClient вообще является убожеством мысли как таковым. Он не даёт над классом Socket никакой другой дополнительной функциональности кроме как одного метода GetStream(). Что мешало добавить GetStream() в сокет — загадка великая есть.


Q>Но точно так же алгоритму могут передать не-null ссылку на объект ссылочного типа, который тоже бросит `System.InvalidOperationException` в методе `GetEnumerator()`.


Могут. Но это будут проблемы того ССЗБ, которому нравится InvalidOperationException.
Мне же нужна возможность конструировать всегда валидные объекты.


V>>Все эти вещи насчет инициализаций структур дефолтными конструкторами надо решать в комплексе

Q>Напомню, что изначально вопрос обобщённых алгоритмов поднимался вне контекста дефолтной инициализации.

Не отмажешься, не пытайся. ))
Структуры принципиально отличаются от ref-типов буквально двумя побочными эффектами:
— дефолтной инициализацией;
— передачей копий значений, в т.ч. через неявный боксинг.
В последнем случае происходят свои приколы — например, в некоем алгоритме будет изменяться содержимое копии, а не целевого экземпляра структуры.

Т.е. контекст был один — дотнет.

Ту ведь как? — ну не понял и не понял, хосподя.
Было бы тебе интересно — переспросил бы.


Q>Просто как утверждение «собаку съел, в поисках классов таких алгоритмов, которые, таки, работают в обоих случаях и в попытках сформулировать ограничения на такие алгоритмы».


Ну? Что не так-то?
Ты ведь не единственный тут такой, которые вместо того, чтобы уточнить подробности (если вообще охота дальше продолжать обсуждение) всегда первым делом переходят в несознанку/отрицалово и требуется десятки постов, чтобы разгрести все эти нагромождения "нет, нет и еще раз нет!".

А чего "нет", куда "нет" и почему вообще "нет"-то?... а ХЗ. Так надо! ))
Законы жанра?


Q>Я же утверждаю, что вполне можно придумывать такие обобщённые алгоритмы с констрейнтами, которым безразлично, передают ли им объекты структур или классов. Вот как суммирование в примере выше.


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

Причем, тут мало того, что таким образом можно хоть как-то задействовать арифметику.
Тут еще чисто вероятностный момент работает — когда надо передать два связанных строгим типовым отношением объекта куда-то, то на порядки сложнее допустить ошибку случайно, в этом месте просыпается внимательность программиста, ЧТД. Потому что есть такая фишка — основная доля ошибок делается в простых местах, в сложных местах ошибок обычно меньше.

Но все-равно, в отуствии ср-в обеспечения гарантий валидности объектов вероятность споткнуться об это остаётся ненулевой, даже для случая оперрования парой типов.

Собсно, моё разочарование в дотнете больше было не от его тормознуточти, а от непоследовательной системы типов, которая больно бъёт по рукам аккурат тогда, когда я пытаюсь с этой тормознутостью бороться, ы-ы-ы! )))
Нифига себе!
"Ах вот вы как? Ну ОК, не больно-то и хотелось..."
Re[13]: Junk in — junk out
Здравствуйте, Qbit86, Вы писали:

Q>Почему этот алгоритм будет работать для reference-типов и не будет для value-типов, или наоборот?


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


Q>Если алгоритму передают некорректный экземпляр value-типа, то алгоритм поведёт себя так же, как если бы ему подали по не-null ссылке некорректный экземпляр reference-типа.


Не туда ты опять смотришь.
Я могу в прикладном виде описать гарантии, которые не дадут мне привести ref-объект в невалидное состояние.
Для value-типов ср-в обеспечения таких гарантий нет.
Однакое, есть сценарии, когда такие гарантии "почти есть".
Например — value-тип являться приватным полем ref-типа и инициализируется в конструкторе.
Помимо этого у обрабатывающих ф-ий стоит модификатор ref в аргументах, что тоже уменьшает вероятность "просто случайно подать".
Помимо этого такие структуры у меня НЕ реализуют известные библиотекам фреймворка интерфейсы, чтобы, опять же, защититься на уровне системы типов от "случайно не туда подали через неявный боксинг".
И т.д. и т.п.
Т.е. я насобирал много правил, помогающих уменьшать вероятность ошибок при проектировании в value-типах, но не смог найти 100% работающей защиты от неправильного использования, т.е. не смог поручить контроль за правильностью использования компилятору. Т.е. только ручками подобную корректность обеспечиваем в любом случае.


Q>Алгоритму могут передать объект значимого типа, который бросит `System.InvalidOperationException` в методе `GetEnumerator()`.


Исключения "not implemented" или "invalid operation" — это первые признаки плохой архитектуры.

Простой пример. Вот есть класс TcpClient.

У него 80% методов выбрасывают "invalid operation".
Почему? Потому что для этого типа оставили пустой конструктор и еще несколько "глупых" конструкторов.
В итоге, объект может находиться в невалидном (неинициализированном) состоянии.
Если убрать пустой конструктор, то у нас пропадает надобность в св-ве Active, а так же уходят все места в его внутреннем коде, которые проверяют это св-во.

В классе TcpClient необходимо было оставить только конструктор от аргументов host+port, а так же добавить конструктор от Socket.
В случае конструирования от Socket можно проверить инвариант сразу, проверив RemoteEndPoint или Connected, т.е. запретить конструировать объект TcpClient в невалидном состоянии.

На самом деле класс TcpClient вообще является убожеством мысли как таковым. Он не даёт над классом Socket никакой другой дополнительной функциональности кроме как одного метода GetStream(). Что мешало добавить GetStream() в сокет — загадка великая есть.


Q>Но точно так же алгоритму могут передать не-null ссылку на объект ссылочного типа, который тоже бросит `System.InvalidOperationException` в методе `GetEnumerator()`.


Могут. Но это будут проблемы того ССЗБ, которому нравится InvalidOperationException.
Мне же нужна возможность конструировать всегда валидные объекты.


V>>Все эти вещи насчет инициализаций структур дефолтными конструкторами надо решать в комплексе

Q>Напомню, что изначально вопрос обобщённых алгоритмов поднимался вне контекста дефолтной инициализации.

Не отмажешься, не пытайся. ))
Структуры принципиально отличаются от ref-типов буквально двумя побочными эффектами:
— дефолтной инициализацией;
— передачей копий значений, в т.ч. через неявный боксинг.
В последнем случае происходят свои приколы — например, в некоем алгоритме будет изменяться содержимое копии, а не целевого экземпляра структуры.

Т.е. контекст был один — дотнет.

Тут ведь как? — ну не понял и не понял, хосподя.
Было бы тебе интересно — переспросил бы.


Q>Просто как утверждение «собаку съел, в поисках классов таких алгоритмов, которые, таки, работают в обоих случаях и в попытках сформулировать ограничения на такие алгоритмы».


Ну? Что не так-то?
Ты ведь не единственный тут такой, которые вместо того, чтобы уточнить подробности (если вообще охота дальше продолжать обсуждение) всегда первым делом переходят в несознанку/отрицалово и требуется десятки постов, чтобы разгрести все эти нагромождения "нет, нет и еще раз нет!".

А чего "нет", куда "нет" и почему вообще "нет"-то?... а ХЗ. Так надо! ))
Законы жанра?


Q>Я же утверждаю, что вполне можно придумывать такие обобщённые алгоритмы с констрейнтами, которым безразлично, передают ли им объекты структур или классов. Вот как суммирование в примере выше.


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

Причем, тут мало того, что таким образом можно хоть как-то задействовать арифметику.
Тут еще чисто вероятностный момент работает — когда надо передать два связанных строгим типовым отношением объекта куда-то, то на порядки сложнее допустить ошибку случайно, в этом месте просыпается внимательность программиста, ЧТД. Потому что есть такая фишка — основная доля ошибок делается в простых местах, в сложных местах ошибок обычно меньше.

Но все-равно, в отуствии ср-в обеспечения гарантий валидности объектов вероятность споткнуться об это остаётся ненулевой, даже для случая оперрования парой типов.

Собсно, моё разочарование в дотнете больше было не от его тормознуточти, а от непоследовательной системы типов, которая больно бъёт по рукам аккурат тогда, когда я пытаюсь с этой тормознутостью бороться, ы-ы-ы! )))
Нифига себе!
"Ах вот вы как? Ну ОК, не больно-то и хотелось..."