Re[27]: Всякие убогие IDE
От: Evgeny.Panasyuk Россия  
Дата: 06.02.17 01:51
Оценка:
Здравствуйте, Somescout, Вы писали:

S>>>Если честно, не понимаю вашей хронической аллергии на C#. Ну да у каждого свои заскоки...

EP>>Не понимаю твоей хронической аллергии на коньяк по утрам. Ну да у каждого свои заскоки...
S>Когда язык программирования сравнивают с алкоголизмом — это сильно. Только вот алкоголик в данной аналогии — вы, а коньяк по утрам — CPP. А в остальном всё верно .

Я сравниваю не язык программирования с алкоголизмом, а твою тупую демагогию с другим известным примером тупой демагогии, но конечно не только лишь все могут понять.
Re[42]: benchmark
От: Evgeny.Panasyuk Россия  
Дата: 06.02.17 02:12
Оценка:
Здравствуйте, netch80, Вы писали:

_>>Ты же наверняка знаешь, что во всех этих языках все методы являются виртуальными функциями (говоря языком C++).

N>Вы тут ну очень много написали, но в следующих ста сообщениях я не увидел возражений, поэтому комментирую. Как это получилось, что ты не в курсе, что в Java и C# просто перевёрнуто умолчание объявления метода виртуальным? Там, где в C++ говорится virtual, в Java молчат, а где в C++ не говорится virtual, в Java говорится final (а в C# — sealed), последствия для виртуальности те же.

Вообще-то это другое, с другими свойствами. final/sealed не делает метод не виртуальным, точнее виртуальный метод вполне может быть final
И кстати final есть и в C++, что я уже выше упоминал.

N>Это чуть упрощая (есть проблемы одноимённых методов и т.п.), но для данных целей сгодится. И видя final — компилятор (пусть JIT) точно так же имеет право рисовать обращение напрямую к нужному методу или инлайнить его.


Вот только в примере
Автор: pilgrim_
Дата: 14.01.17
который разбирался в топике, final в базе A на метод f не поставишь
Отредактировано 06.02.2017 2:15 Evgeny.Panasyuk . Предыдущая версия .
Re[43]: benchmark
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.02.17 05:59
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

_>>>Ты же наверняка знаешь, что во всех этих языках все методы являются виртуальными функциями (говоря языком C++).

N>>Вы тут ну очень много написали, но в следующих ста сообщениях я не увидел возражений, поэтому комментирую. Как это получилось, что ты не в курсе, что в Java и C# просто перевёрнуто умолчание объявления метода виртуальным? Там, где в C++ говорится virtual, в Java молчат, а где в C++ не говорится virtual, в Java говорится final (а в C# — sealed), последствия для виртуальности те же.

EP>Вообще-то это другое, с другими свойствами. final/sealed не делает метод не виртуальным, точнее виртуальный метод вполне может быть final

EP>И кстати final есть и в C++, что я уже выше упоминал.

Формально и в C++ ничто не мешает сделать все методы виртуальными, насколько я помню. Но не делают
Я про то, что если метод не существовал у предков и сразу был объявлен final, то этого достаточно, чтобы его не виртуализовать, и главное, что это общеизвестно и активно используется. И если собеседник этого не знает, но говорит, что "все методы являются виртуальными функциями", то он просто не готов для дискуссии.
А формальности оставьте для language lawyers.

N>>Это чуть упрощая (есть проблемы одноимённых методов и т.п.), но для данных целей сгодится. И видя final — компилятор (пусть JIT) точно так же имеет право рисовать обращение напрямую к нужному методу или инлайнить его.


EP>Вот только в примере
Автор: pilgrim_
Дата: 14.01.17
который разбирался в топике, final в базе A на метод f не поставишь


Не поставишь. Но компилятор уже знает, что тип зависит от , и вполне может внутри себя сделать (псевдокод)

A a;
if (x) { a = new B(); a.B::f(); }
else { a = new C(); a.C::f(); }


и, по тому, что я слышал, так часто и делает.
И разбирался не только этот пример.
The God is real, unless declared integer.
Re[42]: benchmark
От: alex_public  
Дата: 06.02.17 07:17
Оценка:
Здравствуйте, netch80, Вы писали:

_>>Ты же наверняка знаешь, что во всех этих языках все методы являются виртуальными функциями (говоря языком C++).

N>Вы тут ну очень много написали, но в следующих ста сообщениях я не увидел возражений, поэтому комментирую. Как это получилось, что ты не в курсе, что в Java и C# просто перевёрнуто умолчание объявления метода виртуальным? Там, где в C++ говорится virtual, в Java молчат, а где в C++ не говорится virtual, в Java говорится final (а в C# — sealed), последствия для виртуальности те же. Это чуть упрощая (есть проблемы одноимённых методов и т.п.), но для данных целей сгодится.

Не следует путать final (кстати тоже есть в C++, как отдельная сущность) и не виртуальные функции. В отличие от последних final полностью блокирует одно из ключевых преимуществ ООП подхода — расширяемость и кастомизируемость через наследование. Так что если в своём коде ты вполне можешь позволить себе применять данную возможность, то у скажем авторов библиотек ситуация намного печальнее.

Более того, даже если ты при кастомизации какого-нибудь библиотечного класса в своё проекте проставишь ему везде final, то в очень многих ситуациях (а именно, если этот твой класс предназначен для использования библиотекой) это вообще никак не повлияет на ситуацию, т.к. код вызова твоего класса (расположенный внутри библиотеки) всё равно будет записан через его предка.

N>И видя final — компилятор (пусть JIT) точно так же имеет право рисовать обращение напрямую к нужному методу или инлайнить его.

N>Вот если кто не пишет этот final на критически важных местах — он ССЗБ.

Кстати, то, что компилятор имеет такое право в подобном случае, — я согласен. А вот делает ли он это в реальности? Вот конкретный стандартный компилятор java последней версии. Кто-нибудь проверял данный факт?

_>> Что это значит с точки зрения оптимизации? Что компилятор (пусть он даже очень сильный и у него есть куча времени) физически не сможет сделать инлайнинг, потому что просто не знает какой конкретно код в реальности будет вызываться — это определяется только в рантайме. В то время как в C++ не только часто употребимы не виртуальные функции, но и для виртуальных компилятор гарантированно осуществляет инлайнинг, если они вызваны от обычной переменной (а не от указателя или ссылки).

N>И в Java это есть. Кто-то из оракловцев показывал в примерах JIT оптимизации, как компилятор, зная тип, подставлял вызов конкретного метода при работе через ссылку на базовый интерфейс.

Нет, этого нет, потому что физически невозможно (собственно в Java нельзя гарантированно "знать тип" объекта по его объявлению — там без проблем может прятаться какой-то из наследников объявленного, причём чаще всего полученный из какой-то внешней функции).

Насколько я помню некоторые презентации Java по оптимизации, там были упоминанию о некоторых оптимизациях в данной области. Но речь там шла о скорее статистических методах (некий аналог escape анализа), которые срабатывают в редких случаях и после длительного наблюдения за исполнением кода. Думаю не надо объяснять, чем подобное отличается от гарантированного прямого вызова на уровне синтаксиса языка? )
Re[43]: benchmark
От: Evgeny.Panasyuk Россия  
Дата: 06.02.17 07:22
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Кстати, то, что компилятор имеет такое право в подобном случае, — я согласен. А вот делает ли он это в реальности? Вот конкретный стандартный компилятор java последней версии. Кто-нибудь проверял данный факт?


Я ЕМНИП проверял final не некоторых компиляторах C++ — ожидаемый эффект был. Можно легко перепроверить если интересно.
Re[44]: benchmark
От: Evgeny.Panasyuk Россия  
Дата: 06.02.17 07:31
Оценка:
Здравствуйте, netch80, Вы писали:

EP>>Вообще-то это другое, с другими свойствами. final/sealed не делает метод не виртуальным, точнее виртуальный метод вполне может быть final

EP>>И кстати final есть и в C++, что я уже выше упоминал.
N>Формально и в C++ ничто не мешает сделать все методы виртуальными, насколько я помню. Но не делают

Зачем?

N>Я про то, что если метод не существовал у предков и сразу был объявлен final, то этого достаточно, чтобы его не виртуализовать


Даже если он существовал у предков, но в наследнике помечен как final И вызов этого метода идёт именно через наследника — то и в таком случае этого достаточно для прямого вызова

N>и главное, что это общеизвестно и активно используется. И если собеседник этого не знает, но говорит, что "все методы являются виртуальными функциями", то он просто не готов для дискуссии.

N>А формальности оставьте для language lawyers.

И формально и неформально final не применим к обсуждаемому примеру

N>>>Это чуть упрощая (есть проблемы одноимённых методов и т.п.), но для данных целей сгодится. И видя final — компилятор (пусть JIT) точно так же имеет право рисовать обращение напрямую к нужному методу или инлайнить его.

EP>>Вот только в примере
Автор: pilgrim_
Дата: 14.01.17
который разбирался в топике, final в базе A на метод f не поставишь

N>Не поставишь. Но компилятор уже знает, что тип зависит от , и вполне может внутри себя сделать (псевдокод)
N>
N>A a;
N>if (x) { a = new B(); a.B::f(); }
N>else { a = new C(); a.C::f(); }
N>


Я говорю про пример:
A a;
// ...
a.f();
компиляторы C++ делают прямой вызов, даже если f виртуальный и НЕ final.
О таком примере alex_public говорил изначально:

_>но и для виртуальных компилятор гарантированно осуществляет инлайнинг, если они вызваны от обычной переменной (а не от указателя или ссылки).

Re[44]: benchmark
От: alex_public  
Дата: 06.02.17 07:43
Оценка: +1
Здравствуйте, Evgeny.Panasyuk, Вы писали:

_>>Кстати, то, что компилятор имеет такое право в подобном случае, — я согласен. А вот делает ли он это в реальности? Вот конкретный стандартный компилятор java последней версии. Кто-нибудь проверял данный факт?

EP>Я ЕМНИП проверял final не некоторых компиляторах C++ — ожидаемый эффект был. Можно легко перепроверить если интересно.

Ну с C++ то как раз всё понятно, потому что данная конструкция просто заставляет применять основной метод вызова функций в языке. )))

Гораздо интереснее глянуть что с этим в Java и C#. Потому что технически никаких проблем сделать аналогичное нет — это не одна из многих проблемных для Java/C# оптимизаций, недоступных из-за дизайна языка. Но из этого факта совсем не следует автоматический вывод о том, что именно так всё и реализовано. Потому что в JIT компиляторах этих языков в данный момент полно вполне возможных, но не реализованных оптимизаций.
Re[43]: benchmark
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.02.17 09:10
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Не следует путать final (кстати тоже есть в C++, как отдельная сущность) и не виртуальные функции. В отличие от последних final полностью блокирует одно из ключевых преимуществ ООП подхода — расширяемость и кастомизируемость через наследование.


Я не путаю. Задача исключить переопределение в потомке им обеспечивается, а подобные философии тут не интересны.
Тем более что одна из задач final — исключить как раз это "ключевое преимущество" в конкретном месте.

_> Так что если в своём коде ты вполне можешь позволить себе применять данную возможность, то у скажем авторов библиотек ситуация намного печальнее.


Шарповцы в большом количестве стандартных классов размахивают своим sealed направо и налево. Расскажи им про эту печаль.

_>Более того, даже если ты при кастомизации какого-нибудь библиотечного класса в своё проекте проставишь ему везде final, то в очень многих ситуациях (а именно, если этот твой класс предназначен для использования библиотекой) это вообще никак не повлияет на ситуацию, т.к. код вызова твоего класса (расположенный внутри библиотеки) всё равно будет записан через его предка.


А там, где не будет через предка — поможет, и сразу.

_>Кстати, то, что компилятор имеет такое право в подобном случае, — я согласен. А вот делает ли он это в реальности? Вот конкретный стандартный компилятор java последней версии. Кто-нибудь проверял данный факт?


Я видел результаты у соседей по фирме, делает. Сам не щупал, поэтому не показываю.

_>Насколько я помню некоторые презентации Java по оптимизации, там были упоминанию о некоторых оптимизациях в данной области. Но речь там шла о скорее статистических методах (некий аналог escape анализа), которые срабатывают в редких случаях и после длительного наблюдения за исполнением кода. Думаю не надо объяснять, чем подобное отличается от гарантированного прямого вызова на уровне синтаксиса языка? )


В Java всё равно JIT включается не сразу. Поэтому разница не фатальна, и таки да, надо объяснять, чему равно это твоё "длительно".
В C# не щупал, но если они не воспользуются этим при немедленном стартовом JIT, я удивлюсь. Хотя что-то навскидку помню — показывали выход IL, где он вызывал явно, а где через VMT. Так что тоже должно работать.
The God is real, unless declared integer.
Re[45]: benchmark
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.02.17 09:12
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>>>Вообще-то это другое, с другими свойствами. final/sealed не делает метод не виртуальным, точнее виртуальный метод вполне может быть final

EP>>>И кстати final есть и в C++, что я уже выше упоминал.
N>>Формально и в C++ ничто не мешает сделать все методы виртуальными, насколько я помню. Но не делают

EP>Зачем?


Зачем не делают? Думаю, ответ очевиден

N>>Я про то, что если метод не существовал у предков и сразу был объявлен final, то этого достаточно, чтобы его не виртуализовать

EP>Даже если он существовал у предков, но в наследнике помечен как final И вызов этого метода идёт именно через наследника — то и в таком случае этого достаточно для прямого вызова

Именно.

N>>и главное, что это общеизвестно и активно используется. И если собеседник этого не знает, но говорит, что "все методы являются виртуальными функциями", то он просто не готов для дискуссии.

N>>А формальности оставьте для language lawyers.
EP>И формально и неформально final не применим к обсуждаемому примеру

Это ты обсуждаешь пример, а я обсуждаю реплику про то, что в Java всегда виртуальная функция.

EP>Я говорю про пример:

EP>
EP>A a;
EP>// ...
EP>a.f();
EP>
компиляторы C++ делают прямой вызов, даже если f виртуальный и НЕ final.

EP>О таком примере alex_public говорил изначально:
EP>

_>>но и для виртуальных компилятор гарантированно осуществляет инлайнинг, если они вызваны от обычной переменной (а не от указателя или ссылки).


Так про C++ я и не говорил.
The God is real, unless declared integer.
Re[49]: «Собаку съел»
От: samius Япония http://sams-tricks.blogspot.com
Дата: 06.02.17 16:13
Оценка:
Здравствуйте, alex_public, Вы писали:

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


S>>Ты забыл сказать "пожалуйста". Но, я, пожалуй, отвечу таки. Из определения TAPL следует необходимость анализа поведения, будет ли оно разным для разных типов. По Strachey 67 становится ясно что нужно анализировать, будет ли выполняться различный код для каждого типа.


_>Тогда 3 уточняющих вопрос:

_>1. Т.е. у тебя нет разделения на полиморфизм на уровне исходного и машинного кода и ты всегда выводишь для функции объединение обоих критериев (я предпочитаю рассмотреть отдельно на каждом уровне и озвучивать для каждой функции два отдельных результата)?
Нет, такого разделения я не делаю. И не знаю никого, кроме тебя и vdimas-а, кто бы так делал. И объединение обоих критериев я тоже не использую. Я смотрю на поведение.
_>2. Т.е. под фразой "будет ли выполняться различный код для каждого типа" ты подразумеваешь сравнение машинного кода функции, генерируемого для каждого типа или же что-то другое?
Зачем сравнение машинного кода? Достаточно знать, будет ли вызван специфический для типа код. Догадаться об этом можно по execution model или даже по весьма приблизительным представлениям о ней.
_>3. Если в пункте 2, ты говорил про машинный код, то подразумеваешь только сравнение тела функции или же добавляешь к этому ещё и сравнение машинного кода всех других функций из стека вызова нашей?
Хорошо, если даже я не говорил в пункте 2 о машинном коде, то execution model может предполагать стек вызовов. И поэтому можно поговорить и о стеке. Тут я предлагаю на минуту отвлечься от критериев полиморфизма и рассмотреть некое свойство функции g, например, может ли случиться исключение при выполнении g, или обращается ли g к функции h? Если g — обычная функция (не ФВП), то ответ для нее получить довольно просто. Достаточно рассмотреть все ветвления при исполнении. Если мы там обнаружим вызов h или нечто, что может возбудить исключение, станет очевиден ответ на вопрос для функции g. Если g есть ФВП, то поиск ответа становится менее очевиден. Для ответа не достаточно найти функцию f, что g(f) укажет на выполнение h или возбуждение исключения. Хорошо бы еще либо найти такую p, что g(p) не даст такого ответа, либо убедиться что такой функции не существует.

Так вот, если мы нашли такую f, что g(f) возбуждает исключение и p что g(p) не возбуждает, то это как бы намекает на то, что сама g не обладает проверяемым свойством, что оно наведенное переданным параметром.

Есть надежда что по вышеописанному у тебя схожая позиция.

Так вот, проверка наличия вызова специального кода для параметра типа — она ничем не отличается от вышеописанной проверки по возбуждению исключения либо проверки на обращение к h.
Возвращаясь к баранам — apply может быть вызвана как с функцией, которая не использует специальный код для разных типов, так и с функцией, которая его использует. Но ты мне почему-то предлагаешь судить о свойстве apply лишь по одному примеру, отбрасывая противоположные. Причем, делаешь вид что это я будто бы предлагаю.

S>>>>http://rsdn.org/forum/flame.comp/6676499.1
Автор: samius
Дата: 24.01.17

S>>>>http://rsdn.org/forum/flame.comp/6677933.1
Автор: samius
Дата: 25.01.17

_>>>В данные цитатах нет ни одного слова про подобное. Или у тебя своё особое понимание и английского языка?
S>>Особое от твоего — точно. Я вот в этих определениях не увидел ничего про "тело функции". А ты — увидел.

_>Ха, так я то как раз не пытаюсь прятаться за чужие цитаты, а говорю именно свою точку зрения. Но при этом она неплохо совместима с этими известными цитатами. А вот ты наоборот пытаешься сделать вид, что высказываемый тобой бред является прямым следствием из этих цитат, хотя в них нет ничего даже отдалённо похожего.

Интересно, на что по-твоему похожа фраза "function may execute different code for each type of argument"? Опиши, пожалуйста, своими словами, не отрываясь от своей теории полиморфизма в тексте. Приведи примеры функций, которые обладают и не обладают данным свойством.

_>>>И? ) Тебе что-то не нравится? )

S>>То, что различный код для equal_to выполняется, но ты уперся "в тело".

_>На низком уровне различный код исполняется всегда (хотя бы потому что ЦПУ у нас по сути ad hoc). И соответственно если следовать твоей логике, то само понятие параметрического полиморфизма теряет смысл для подавляющей части реального кода.

Да, вспомнил как ты трактуешь "всегда" и "абсолютно никогда". А тут еще и "смысл", "подавляющей", "части" и "реального". Улыбнуло. Ну и что, зато для "остальной" части реального кода понятие смысл не теряет.

S>>Ничего не получается такого с ФВП. apply параметрически полиморфна.


_>Это согласно моей точки зрения. И так же согласно твоим отдельным заявлениям. А теперь (когда ты конкретизируешь те 3 пункта в начале сообщения) мы посмотрим получается ли тоже самое из твоего определения критериев. И соответственно если не получится, то будем в очередной раз громко смеяться.

Да пожалуйста.

_>>>Ну и насчёт чистоты... Если уж ты заикнулся про это, то должен знать, что в том же Хаскеле есть известные механизмы для изоляции "грязного кода", так что в определённых случаях он вполне может располагаться внутри чистой функции. Как раз очень хорошая аналогия наблюдается... )))

S>>Аналогия чему? Ты хочешь сказать что map стала перманентно грязной от того что ты в нее смог однажды подсунуть изолированную грязную функцию?

_>Ты снова путаешь свои взгляды и мои?) В моих как раз на поведение apply ничего не влияет. )

В моих — поведение apply не влияет на поведение той функции, что ей передают. А apply — вообще никаким своим поведением, отличающим ее от поведения того, что ей передали, не обладает.

_>А по поводу аналогии очевидно же. Возьмём мой пример my_equal_to на C++. Он использует некий тип eq, который как раз и осуществляет изоляцию ad hoc кода в себе, так что вызов его оператора равенства из my_equal_to получается параметрически полиморфным (такой оператор опять же ровно один для всех типов, и в исходных кодах и в машинных).

Только лишь с оговоркой что my_equal_to вызываает различный код при различных типах и, в соответствии с вызываемым кодом, меняет и свое поведение от типа к типу.

S>>Один раз ты сравнил поведения двух различных функций, у которых различная реализация на уровне машинных кодов. При этом сказал что поведение будет "как у", т.е. одинаковое. Я полагаю, ты интуитивно использовал procedural abstraction.


_>Непонятно зачем ты постоянно приплетаешь данный термин из области методологии разработки ПО. У нас же вроде как чисто техническая дискуссия.

Разве? Когда ты смотришь чисто на исходный код — где тут техническая дискуссия?

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

Твой вопрос имеет отношение к "технической" дискуссии?

S>>В этом же сообщении ты в отношении другой (других функций) my_equal_to заявил что их поведение абсолютно одинаковое, но при этом перешел от поведения функций к поведению исполнителя при очевидно разном поведении функций на уровне procedural abstraction для разных типов.


_>Ээээ что? ) У меня такое впечатление, что ты хочешь сказать, что слово "поведение" является каким-то программистским термином, а не просто общеупотребимым словом с очевидным значением. Если ты реально так считаешь, то я буду рад, если ты и меня просветишь в этом вопросе (естественно со ссылками на определение данного "термина"). А то мало ли, вдруг я действительно не в курсе и такой интересный термин реально существует...

Термин-то обычный бытовой. Но имеет значение, чего именно поведение ты рассматриваешь. Говоря о поведении функции, имеет смысл рассматривать поведение именно функции, а не переходить к подробностям ее реализации на определенной платформе определенной версии компилятора с определенными опциями.

S>>

S>>>твоя my_equal_to абсолютно и полностью укладывается.
S>>Не укладывается, т.к. поведение абсолютно одинаковое: вызов оператора равенства для соответствующего типа. )

S>>То есть у тебя слово "поведение" вызывает некий диссонанс, что может объяснять проблемы понимания определений, использующих слово "поведение".
S>>И если в определениях использовать твой первый вариант (процедурной абтракции), то как раз и выйдет, что функция my_equal_to ведет себя по разному для разных типов, а значит вписывается в ad-hoc.
S>>Но ты почему-то уперся и используешь второе понятие — поведение исполнителя (через вызов оператора).

_>С трудом понял о чём ты говоришь, настолько странно ты используешь (а точнее чаще вообще не используешь) терминологию нашей отрасли. По сути ты здесь хочешь предложить включать во внешний контракт функции my_equal_to не только тот факт, что она производит сравнение полиморфных типов, но и то, что она это делает обязательно с помощью вызовов операторов равенства соответствующих типов. Но это на самом деле не верно. Потому как в реальности происходит вызов не этих операторов, а оператора равенства типа eq (что легко проверить чуть поменяв этот тип так, чтобы он перестал захватывать и использовать пользовательские операторы). Вот данный факт (про использования оператора равенства eq) вполне возможно стоит рассматривать как часть внешнего контракта my_equal_to. Однако он явно не будет свидетельствовать об ad hoc природе my_equal_to.

Возвращаясь к поведению my_equal_to — оно разное в зависимости от разных типов. Я говорю здесь о поведении функции, о свойствах отображения, если переводить на язык математической абстракции. А не о том, что она вызовет и вообще вызывает ли.

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

Вот смотри (цитата с http://www.cplusplus.com/reference/string/char_traits/eq/)

Returns whether characters c and d are considered equal.

In the standard specializations of char_traits, this function behaves as the built-in operator==, but custom character traits classes may provide an alternative behavior.

Перевести тебе выделенное? Здесь пишут что "эта функция ведет себя как встроенный оператор ==". Они пишут не о том, как ведет себя реализация функции (что она там вызывает). Они пишут о схожем поведении с чем-то еще. Если бы они сказали что eq что-то вызывает, а не ведет себя подобнымм образом, пришлось бы скрывать то что она ведет себя подобным образом, ибо реализация == может уже третьего оператора не вызывать. Итого, факт вызова — это не касается поведения функции. Это за гранью procedural abstraction.

То есть ты со своим вниманием к мелкой оптимизации просто выпал из терминов, на котором описаны функции в cplusplus.com. Или там кто-то поработал из секты свидетельства ad-hoc полиморфизма. Потому, тебе придется и их вычеркнуть из списка доверенных источников, если уже не выкинул, как хаскельвики.

S>>Хотя, заметь! Сам ты используешь оба смысла слова "поведение", причем, даже в одном посте, и наверняка с разницей не более пары минут.


_>Вообще то мне известно всего одно значение слова "поведение" (причём и оно то не "компьютерное"), так что использовать какие-то два его смысла я бы не смог физически. )

Так это был не ты? Или ты используя единственный смысл слова "поведение" всего лишь перескочил от функции к ее частной реализации?
Re[44]: benchmark
От: alex_public  
Дата: 06.02.17 22:08
Оценка:
Здравствуйте, netch80, Вы писали:

_>>Не следует путать final (кстати тоже есть в C++, как отдельная сущность) и не виртуальные функции. В отличие от последних final полностью блокирует одно из ключевых преимуществ ООП подхода — расширяемость и кастомизируемость через наследование.

N>Я не путаю. Задача исключить переопределение в потомке им обеспечивается, а подобные философии тут не интересны.
N>Тем более что одна из задач final — исключить как раз это "ключевое преимущество" в конкретном месте.

С этой задачей то final конечно без проблем справляется. Только вот ты похоже забыл, что в данной дискуссии обсуждаются оптимизации и соответственно задача совсем другая стоит. А именно: обеспечить наиболее эффективный вызов функций, причём желательно не вводя при этом никаких ограничений на код. И вот как раз со второй частью у final проблемы. )

_>> Так что если в своём коде ты вполне можешь позволить себе применять данную возможность, то у скажем авторов библиотек ситуация намного печальнее.

N>Шарповцы в большом количестве стандартных классов размахивают своим sealed направо и налево. Расскажи им про эту печаль.

Не знаю где они там и чем размахивают, но в любом случае сильно сомневаюсь, что sealed там активно применяется именно для оптимизаций. Скорее для архитектурных целей, так же как и final в C++. Просто потому что в C# вполне себе имеются не виртуальные функции, как и в C++. ))) Так что данная проблема C# не касается — для него актуальна только вторая проблема (об оптимизации именно виртуальных вызовов), следующая из обязательной ссылочной природы всех экземпляров классов.

_>>Кстати, то, что компилятор имеет такое право в подобном случае, — я согласен. А вот делает ли он это в реальности? Вот конкретный стандартный компилятор java последней версии. Кто-нибудь проверял данный факт?

N>Я видел результаты у соседей по фирме, делает. Сам не щупал, поэтому не показываю.

ОК, вполне возможно. Вообще я не раз замечал, что хотя сам язык C# кажется намного лучше приспособленным для эффективного кода, но при этом компилятор Java явно лучше оптимизирует.

_>>Насколько я помню некоторые презентации Java по оптимизации, там были упоминанию о некоторых оптимизациях в данной области. Но речь там шла о скорее статистических методах (некий аналог escape анализа), которые срабатывают в редких случаях и после длительного наблюдения за исполнением кода. Думаю не надо объяснять, чем подобное отличается от гарантированного прямого вызова на уровне синтаксиса языка? )

N>В Java всё равно JIT включается не сразу. Поэтому разница не фатальна, и таки да, надо объяснять, чему равно это твоё "длительно".

Да дело даже не в сроках, а именно в недетерминированной природе этого явления. ) Так же как и у escape анализа. Т.е. понятно что лучше так, чем никак (в том же C# вроде вообще не особо применяются оптимизации "на лету"). Но не стоит даже сравнивать подобное с детерминированными аналогами — подобные решения делают скорее от безысходности (проблем в архитектуре), а не от хорошей жизни.

N>В C# не щупал, но если они не воспользуются этим при немедленном стартовом JIT, я удивлюсь. Хотя что-то навскидку помню — показывали выход IL, где он вызывал явно, а где через VMT. Так что тоже должно работать.


В этой темке народ тестировал — по их словам не работает такая оптимизация в C#.
Re[50]: «Собаку съел»
От: alex_public  
Дата: 07.02.17 00:29
Оценка:
Здравствуйте, samius, Вы писали:

_>>Тогда 3 уточняющих вопрос:

_>>1. Т.е. у тебя нет разделения на полиморфизм на уровне исходного и машинного кода и ты всегда выводишь для функции объединение обоих критериев (я предпочитаю рассмотреть отдельно на каждом уровне и озвучивать для каждой функции два отдельных результата)?
S>Нет, такого разделения я не делаю. И не знаю никого, кроме тебя и vdimas-а, кто бы так делал. И объединение обоих критериев я тоже не использую. Я смотрю на поведение.

Я вижу смысл в таком разделение по той причине, что имеются языки с разным видом полиморфизма на уровне исходного кода и на уровне машинного. Т.е. очевидно параметрически полиморфная функция на уровне исходного кода, может иметь ad hoc реализацию (причём программист может об этом даже не знать, как часто бывает например в том же Хаскеле) на уровне машинных кодов.

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

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

_>>2. Т.е. под фразой "будет ли выполняться различный код для каждого типа" ты подразумеваешь сравнение машинного кода функции, генерируемого для каждого типа или же что-то другое?

S>Зачем сравнение машинного кода?

Как это зачем? Ты же сам в предыдущем сообщение чётко ответил, что одного анализа исходного кода недостаточно. А если недостаточно анализа исходного кода, то что ещё остаётся то? Только генерируемый по нему машинный... Или ты знаешь ещё что-то, что можно проанализировать у некого "куска кода"? )

S>Достаточно знать, будет ли вызван специфический для типа код. Догадаться об этом можно по execution model или даже по весьма приблизительным представлениям о ней.


Ну т.е. получается что всё же исходников достаточно? ))) Или как? )

_>>3. Если в пункте 2, ты говорил про машинный код, то подразумеваешь только сравнение тела функции или же добавляешь к этому ещё и сравнение машинного кода всех других функций из стека вызова нашей?

S>Хорошо, если даже я не говорил в пункте 2 о машинном коде, то execution model может предполагать стек вызовов. И поэтому можно поговорить и о стеке. Тут я предлагаю на минуту отвлечься от критериев полиморфизма и рассмотреть некое свойство функции g, например, может ли случиться исключение при выполнении g, или обращается ли g к функции h? Если g — обычная функция (не ФВП), то ответ для нее получить довольно просто. Достаточно рассмотреть все ветвления при исполнении. Если мы там обнаружим вызов h или нечто, что может возбудить исключение, станет очевиден ответ на вопрос для функции g. Если g есть ФВП, то поиск ответа становится менее очевиден. Для ответа не достаточно найти функцию f, что g(f) укажет на выполнение h или возбуждение исключения. Хорошо бы еще либо найти такую p, что g(p) не даст такого ответа, либо убедиться что такой функции не существует.
S>Так вот, если мы нашли такую f, что g(f) возбуждает исключение и p что g(p) не возбуждает, то это как бы намекает на то, что сама g не обладает проверяемым свойством, что оно наведенное переданным параметром.
S>Есть надежда что по вышеописанному у тебя схожая позиция.
S>Так вот, проверка наличия вызова специального кода для параметра типа — она ничем не отличается от вышеописанной проверки по возбуждению исключения либо проверки на обращение к h.

О, великолепный пример. Хотя конечно же всем известно, что аналогия не является доказательством. Но тут она так красиво демонстрирует именно мою точку зрения, что прямо не могу удержаться. И так, смотри на такой простейший код:
void f() {throw "Ou!";}
void g() {try{ f(); }catch(...){}}
void h() {g();}

Теперь внимание фокус:
Вопрос: происходит ли в процессе выполнения функции h возбуждение исключений (читай: происходит ли в процессе выполнения my_equal_to исполнение ad hoc кода?)?
Ответ: да.
Вопрос: является ли функция h источником исключений (читай: является ли функция my_equal_to ad hoc полиморфной?)?
Ответ: нет.

Ну и для полной ясности аналогии уточню: f=="операторы равенства всех типов", g=="оператор равенства для eq", h==my_equal_to.

S>Возвращаясь к баранам — apply может быть вызвана как с функцией, которая не использует специальный код для разных типов, так и с функцией, которая его использует. Но ты мне почему-то предлагаешь судить о свойстве apply лишь по одному примеру, отбрасывая противоположные. Причем, делаешь вид что это я будто бы предлагаю.


Т.е. ты тут хочешь сказать, что с твоей точки зрения вид полиморфизма функции apply нельзя определить без уточнения её параметров, правильно?

_>>Ха, так я то как раз не пытаюсь прятаться за чужие цитаты, а говорю именно свою точку зрения. Но при этом она неплохо совместима с этими известными цитатами. А вот ты наоборот пытаешься сделать вид, что высказываемый тобой бред является прямым следствием из этих цитат, хотя в них нет ничего даже отдалённо похожего.

S>Интересно, на что по-твоему похожа фраза "function may execute different code for each type of argument"? Опиши, пожалуйста, своими словами, не отрываясь от своей теории полиморфизма в тексте. Приведи примеры функций, которые обладают и не обладают данным свойством.

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

_>>На низком уровне различный код исполняется всегда (хотя бы потому что ЦПУ у нас по сути ad hoc). И соответственно если следовать твоей логике, то само понятие параметрического полиморфизма теряет смысл для подавляющей части реального кода.

S>Да, вспомнил как ты трактуешь "всегда" и "абсолютно никогда". А тут еще и "смысл", "подавляющей", "части" и "реального". Улыбнуло. Ну и что, зато для "остальной" части реального кода понятие смысл не теряет.

Ну раз так, то давай спрошу проще. Приведи примерчик реальной (т.е. не ту симпатичную константную функцию) параметрически полиморфной (согласно твоим критериям) функции. Ну чтобы мы наконец увидели как такое чудо выглядит... )

_>>Ээээ что? ) У меня такое впечатление, что ты хочешь сказать, что слово "поведение" является каким-то программистским термином, а не просто общеупотребимым словом с очевидным значением. Если ты реально так считаешь, то я буду рад, если ты и меня просветишь в этом вопросе (естественно со ссылками на определение данного "термина"). А то мало ли, вдруг я действительно не в курсе и такой интересный термин реально существует...

S>Термин-то обычный бытовой. Но имеет значение, чего именно поведение ты рассматриваешь. Говоря о поведении функции, имеет смысл рассматривать поведение именно функции, а не переходить к подробностям ее реализации на определенной платформе определенной версии компилятора с определенными опциями.

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

_>>С трудом понял о чём ты говоришь, настолько странно ты используешь (а точнее чаще вообще не используешь) терминологию нашей отрасли. По сути ты здесь хочешь предложить включать во внешний контракт функции my_equal_to не только тот факт, что она производит сравнение полиморфных типов, но и то, что она это делает обязательно с помощью вызовов операторов равенства соответствующих типов. Но это на самом деле не верно. Потому как в реальности происходит вызов не этих операторов, а оператора равенства типа eq (что легко проверить чуть поменяв этот тип так, чтобы он перестал захватывать и использовать пользовательские операторы). Вот данный факт (про использования оператора равенства eq) вполне возможно стоит рассматривать как часть внешнего контракта my_equal_to. Однако он явно не будет свидетельствовать об ad hoc природе my_equal_to.

S>Возвращаясь к поведению my_equal_to — оно разное в зависимости от разных типов. Я говорю здесь о поведении функции, о свойствах отображения, если переводить на язык математической абстракции. А не о том, что она вызовет и вообще вызывает ли.

Поведение как раз одинаковое — см. ниже.

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

S>Вот смотри (цитата с http://www.cplusplus.com/reference/string/char_traits/eq/)
S>

S>Returns whether characters c and d are considered equal.

S>In the standard specializations of char_traits, this function behaves as the built-in operator==, but custom character traits classes may provide an alternative behavior.

S>Перевести тебе выделенное? Здесь пишут что "эта функция ведет себя как встроенный оператор ==". Они пишут не о том, как ведет себя реализация функции (что она там вызывает). Они пишут о схожем поведении с чем-то еще. Если бы они сказали что eq что-то вызывает, а не ведет себя подобнымм образом, пришлось бы скрывать то что она ведет себя подобным образом, ибо реализация == может уже третьего оператора не вызывать. Итого, факт вызова — это не касается поведения функции. Это за гранью procedural abstraction.

Вообще то сомнительная цитата (см. ниже), но если тебе очень хочется говорить именно в таких терминах, то никаких проблем нет — я могу сформулировать и в таких. И так правильная формулировка в таких терминах: функция my_equal_to ведёт себя как оператор равенства класса eq.

S>То есть ты со своим вниманием к мелкой оптимизации просто выпал из терминов, на котором описаны функции в cplusplus.com. Или там кто-то поработал из секты свидетельства ad-hoc полиморфизма. Потому, тебе придется и их вычеркнуть из списка доверенных источников, если уже не выкинул, как хаскельвики.


Хы, вообще то cplusplus.com действительно давно протух и все знакомые с C++ программисты давным давно пользуются этим http://en.cppreference.com/w/cpp/string/char_traits/cmp (кстати можешь сравнить формулировку здесь и твою цитату) ресурсом. Но на нашу дискуссию данный факт никак не влияет, т.к. твои мелкие цепляния к формулировкам никак не меняют суть происходящего. )))
Re[26]: Illusion of transparency
От: vdimas Россия  
Дата: 07.02.17 06:36
Оценка:
Здравствуйте, Somescout, Вы писали:

V>>Предлагаю завязывать, бо мне уже трудно сдерживать откровенное глумление...

S>Да уж... "Ха-ха! На самом деле это был ТЕСТ!!! И вы его НЕ ПРОШЛИ!!111"

Если бы.
Там всё всерьёз.


V>>Столько было пафоса и такой пффф... Не могу отучить себя реагировать на такую комбинацию ))

S>Извините, давно читали свои сообщения? Ощущение, что круг вашего общения ограничен исключительно форумом.

Не надо льстить человечеству. За пределами этого форума всё еще намного печальнее))
Re[51]: «Собаку съел»
От: samius Япония http://sams-tricks.blogspot.com
Дата: 07.02.17 18:38
Оценка: +1
Здравствуйте, alex_public, Вы писали:

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


S>>Нет, такого разделения я не делаю. И не знаю никого, кроме тебя и vdimas-а, кто бы так делал. И объединение обоих критериев я тоже не использую. Я смотрю на поведение.


_>Я вижу смысл в таком разделение по той причине, что имеются языки с разным видом полиморфизма на уровне исходного кода и на уровне машинного. Т.е. очевидно параметрически полиморфная функция на уровне исходного кода, может иметь ad hoc реализацию (причём программист может об этом даже не знать, как часто бывает например в том же Хаскеле) на уровне машинных кодов.

У исходного кода без execution model нет поведения, т.е. говорить не о чем, только об факте включения некоторого подтекста. Но при рассмотрении текста в совокупности с execution model, получается поведение и однозначная классификация полиморфизма по поведению.

_>Но я естественно не настаиваю на том, чтобы мои собеседники тоже пользовались подобным разделением. Это я просто пояснил причины такого подхода.

Спасибо, но что-то я замечаю некоторую тавтологию. Ты вводишь полиморфизм исходного и полиморфизм машинного лишь для того что бы иметь возможность говорить о том что функции ведут себя одним образом на уровне исходников и другим на уровне машинных кодов. А зачем тебе такое — ты не поясняешь. Чего ради-то?

_>Однако если ты пользуешься другим подходом, то его желательно сформулировать (что ты не можешь уже сколько сообщений подряд), чтобы мы могли понимать друг друга.

Я просто уже не знаю, как тебе говорить о поведении. Я тебе говорю о поведении — ты мне об исходниках.

_>>>2. Т.е. под фразой "будет ли выполняться различный код для каждого типа" ты подразумеваешь сравнение машинного кода функции, генерируемого для каждого типа или же что-то другое?

S>>Зачем сравнение машинного кода?

_>Как это зачем? Ты же сам в предыдущем сообщение чётко ответил, что одного анализа исходного кода недостаточно. А если недостаточно анализа исходного кода, то что ещё остаётся то? Только генерируемый по нему машинный... Или ты знаешь ещё что-то, что можно проанализировать у некого "куска кода"? )

Знаю, но уже не знаю, как тебе об этом сказать. Пытаюсь, но ты все время думаешь что я что-то скрываю.

S>>Достаточно знать, будет ли вызван специфический для типа код. Догадаться об этом можно по execution model или даже по весьма приблизительным представлениям о ней.


_>Ну т.е. получается что всё же исходников достаточно? ))) Или как? )

В совокупности с execution model — наверняка.

S>>Есть надежда что по вышеописанному у тебя схожая позиция.

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

_>О, великолепный пример. Хотя конечно же всем известно, что аналогия не является доказательством. Но тут она так красиво демонстрирует именно мою точку зрения, что прямо не могу удержаться. И так, смотри на такой простейший код:

_>
_>void f() {throw "Ou!";}
_>void g() {try{ f(); }catch(...){}}
_>void h() {g();}
_>

_>Теперь внимание фокус:
_>Вопрос: происходит ли в процессе выполнения функции h возбуждение исключений (читай: происходит ли в процессе выполнения my_equal_to исполнение ad hoc кода?)?
_>Ответ: да.
_>Вопрос: является ли функция h источником исключений (читай: является ли функция my_equal_to ad hoc полиморфной?)?
_>Ответ: нет.
То есть ты взял и один вопрос, ответ на который требует просмотра всего ветвления, якобы "по аналогии" подменил на другой вопрос, ответ на который не требует просмотра всего ветвления (как минимум, в частном случае). Неплохо, но я не прослеживаю в твоем примере аналогиии с проверкой на факт выполнения некого специального кода. Зубы заговариваешь?

_>Ну и для полной ясности аналогии уточню: f=="операторы равенства всех типов", g=="оператор равенства для eq", h==my_equal_to.


S>>Возвращаясь к баранам — apply может быть вызвана как с функцией, которая не использует специальный код для разных типов, так и с функцией, которая его использует. Но ты мне почему-то предлагаешь судить о свойстве apply лишь по одному примеру, отбрасывая противоположные. Причем, делаешь вид что это я будто бы предлагаю.


_>Т.е. ты тут хочешь сказать, что с твоей точки зрения вид полиморфизма функции apply нельзя определить без уточнения её параметров, правильно?

Не правильно. apply не вызывает никакого специального кода прямо или косвенно до тех пор, пока ей не подадут явно через параметр такой код прямо или косвенно. В то время, как equal_to и my_equal_to просто неотделимы от выполнения специального кода для каждого типа.

_>>>Ха, так я то как раз не пытаюсь прятаться за чужие цитаты, а говорю именно свою точку зрения. Но при этом она неплохо совместима с этими известными цитатами. А вот ты наоборот пытаешься сделать вид, что высказываемый тобой бред является прямым следствием из этих цитат, хотя в них нет ничего даже отдалённо похожего.

S>>Интересно, на что по-твоему похожа фраза "function may execute different code for each type of argument"? Опиши, пожалуйста, своими словами, не отрываясь от своей теории полиморфизма в тексте. Приведи примеры функций, которые обладают и не обладают данным свойством.

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

Но ты в упор не хочешь замечать что под фразу "function may execute different code for each type of argument" подходят функции, которые явно вызывают перегрузки функций, или ведут себя в точности как соответствующие перегрузки для каждого типа. Хорошо, только я бы не стал называть такую точку зрения "неплохо совместимой" с этими цитатами. Но ты можешь продолжать называть ее так, несмотря на мое мнение. Вобщем, нашли точку где наши знания английского явно расходятся (да и русского тоже, если фразу перевести).

_>>>На низком уровне различный код исполняется всегда (хотя бы потому что ЦПУ у нас по сути ad hoc). И соответственно если следовать твоей логике, то само понятие параметрического полиморфизма теряет смысл для подавляющей части реального кода.

S>>Да, вспомнил как ты трактуешь "всегда" и "абсолютно никогда". А тут еще и "смысл", "подавляющей", "части" и "реального". Улыбнуло. Ну и что, зато для "остальной" части реального кода понятие смысл не теряет.

_>Ну раз так, то давай спрошу проще. Приведи примерчик реальной (т.е. не ту симпатичную константную функцию) параметрически полиморфной (согласно твоим критериям) функции. Ну чтобы мы наконец увидели как такое чудо выглядит... )

Prelude> just a = Just a
Prelude> :t just
just :: a -> Maybe a

Еще одну?

S>>Термин-то обычный бытовой. Но имеет значение, чего именно поведение ты рассматриваешь. Говоря о поведении функции, имеет смысл рассматривать поведение именно функции, а не переходить к подробностям ее реализации на определенной платформе определенной версии компилятора с определенными опциями.


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

О, наметился прогресс. 6-го числа было так

так что использовать какие-то два его смысла я бы не смог физически. )

А тут уже в любых. Рад за тебя.

S>>Возвращаясь к поведению my_equal_to — оно разное в зависимости от разных типов. Я говорю здесь о поведении функции, о свойствах отображения, если переводить на язык математической абстракции. А не о том, что она вызовет и вообще вызывает ли.


_>Поведение как раз одинаковое — см. ниже.

Не ну чушь. У сравнения поведение разное для разных типов.

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

S>>Вот смотри (цитата с http://www.cplusplus.com/reference/string/char_traits/eq/)
S>>

S>>Returns whether characters c and d are considered equal.

S>>In the standard specializations of char_traits, this function behaves as the built-in operator==, but custom character traits classes may provide an alternative behavior.

S>>Перевести тебе выделенное? Здесь пишут что "эта функция ведет себя как встроенный оператор ==". Они пишут не о том, как ведет себя реализация функции (что она там вызывает). Они пишут о схожем поведении с чем-то еще. Если бы они сказали что eq что-то вызывает, а не ведет себя подобнымм образом, пришлось бы скрывать то что она ведет себя подобным образом, ибо реализация == может уже третьего оператора не вызывать. Итого, факт вызова — это не касается поведения функции. Это за гранью procedural abstraction.

_>Вообще то сомнительная цитата (см. ниже), но если тебе очень хочется говорить именно в таких терминах, то никаких проблем нет — я могу сформулировать и в таких. И так правильная формулировка в таких терминах: функция my_equal_to ведёт себя как оператор равенства класса eq.

ты не договорил. Она ведет себя так же как eq — то есть по разному, в зависимости от типа. Иными словами — специальным образом (ad hoc).

S>>То есть ты со своим вниманием к мелкой оптимизации просто выпал из терминов, на котором описаны функции в cplusplus.com. Или там кто-то поработал из секты свидетельства ad-hoc полиморфизма. Потому, тебе придется и их вычеркнуть из списка доверенных источников, если уже не выкинул, как хаскельвики.


_>Хы, вообще то cplusplus.com действительно давно протух и все знакомые с C++ программисты давным давно пользуются этим http://en.cppreference.com/w/cpp/string/char_traits/cmp (кстати можешь сравнить формулировку здесь и твою цитату) ресурсом. Но на нашу дискуссию данный факт никак не влияет, т.к. твои мелкие цепляния к формулировкам никак не меняют суть происходящего. )))

Ощутимой разницы в формулировке не нашел, наверное и cppreferencce.com тоже протух. Итого, получается что твоей точке зрения способствует лишь весьма своеобразная трактовка фразы "function may execute different code for each type of argument". Все остальное (хаскельвики, википедия, cpp ресурсы) — по-твоему тухлое. Но ты — весь в белом. И это тоже не меняет суть происходящего, а есть сама суть.
Re[52]: «Собаку съел»
От: alex_public  
Дата: 10.02.17 21:56
Оценка:
Здравствуйте, samius, Вы писали:

_>>Я вижу смысл в таком разделение по той причине, что имеются языки с разным видом полиморфизма на уровне исходного кода и на уровне машинного. Т.е. очевидно параметрически полиморфная функция на уровне исходного кода, может иметь ad hoc реализацию (причём программист может об этом даже не знать, как часто бывает например в том же Хаскеле) на уровне машинных кодов.

S>У исходного кода без execution model нет поведения, т.е. говорить не о чем, только об факте включения некоторого подтекста. Но при рассмотрении текста в совокупности с execution model, получается поведение и однозначная классификация полиморфизма по поведению.

Мне вот интересно, а ты способен вообще начать формулировать свои мысли с помощью технической терминологии, а не бытовой? А то понятие "поведение" же можно интерпретировать как угодно. Например вот возьму я две одинаковые функции, определённые отдельно (перегрузка) для float и для double и скажу что у них абсолютно одинаковое поведение (скажем "сложение чисел с плавающей точкой"). С твоей позиции это получается параметрический полиморфизм? )))

_>>Но я естественно не настаиваю на том, чтобы мои собеседники тоже пользовались подобным разделением. Это я просто пояснил причины такого подхода.

S>Спасибо, но что-то я замечаю некоторую тавтологию. Ты вводишь полиморфизм исходного и полиморфизм машинного лишь для того что бы иметь возможность говорить о том что функции ведут себя одним образом на уровне исходников и другим на уровне машинных кодов. А зачем тебе такое — ты не поясняешь. Чего ради-то?

Я не ввожу разные полиморфизмы — классическое определение с безликим "код" вполне мне подходит. Я просто применяю его на двух отдельных уровнях размышления.

_>>Однако если ты пользуешься другим подходом, то его желательно сформулировать (что ты не можешь уже сколько сообщений подряд), чтобы мы могли понимать друг друга.

S>Я просто уже не знаю, как тебе говорить о поведении. Я тебе говорю о поведении — ты мне об исходниках.

Потому что нет такого термина как поведение. Сформулируй свою мысль в технических терминах, а не так, чтобы его можно было интерпретировать как угодно, в зависимости от выгоды конкретной ситуации.

_>>Ну т.е. получается что всё же исходников достаточно? ))) Или как? )

S>В совокупности с execution model — наверняка.

Вот любишь ты использовать скользкие понятия. Вот скажи мне, например в случае Хаскеля в его "execution model" входит тот факт, что в языке есть только функции одного аругмента (а запись вроде как функции нескольких просто является упрощённой записью последовательности нескольких вызовов)? Или же там наоборот указано, что данные объявления последовательностей вызовов в реальности превращаются в классические функции многих аргументов? )

_>>Т.е. ты тут хочешь сказать, что с твоей точки зрения вид полиморфизма функции apply нельзя определить без уточнения её параметров, правильно?

S>Не правильно. apply не вызывает никакого специального кода прямо или косвенно до тех пор, пока ей не подадут явно через параметр такой код прямо или косвенно.

И? ) Так какой тогда полиморфизм у apply? )

S>В то время, как equal_to и my_equal_to просто неотделимы от выполнения специального кода для каждого типа.


Ну вообще то это не так даже для equal_to, т.к. мы можем определить единый для всех типов оператор равенства (понятно что смысла в подобном мало, но сам факт подобной возможности однозначен). А уж для my_equal_to это на 100% не верно, потому как в ней происходит вполне себе параметрически полиморфный вызов оператора равенства для типа eq и всё — что там происходит внутри этого оператора (разный код для разных типов или нет) my_equal_to не касается.

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

S>Но ты в упор не хочешь замечать что под фразу "function may execute different code for each type of argument" подходят функции, которые явно вызывают перегрузки функций, или ведут себя в точности как соответствующие перегрузки для каждого типа. Хорошо, только я бы не стал называть такую точку зрения "неплохо совместимой" с этими цитатами. Но ты можешь продолжать называть ее так, несмотря на мое мнение. Вобщем, нашли точку где наши знания английского явно расходятся (да и русского тоже, если фразу перевести).

Ну да, интерпретировать "исполняют разный код для разных типов" в "ведут себя в точности как соответствующие перегрузки" — это очень забавно. )))

_>>Ну раз так, то давай спрошу проще. Приведи примерчик реальной (т.е. не ту симпатичную константную функцию) параметрически полиморфной (согласно твоим критериям) функции. Ну чтобы мы наконец увидели как такое чудо выглядит... )

S>
S>Prelude> just a = Just a
S>Prelude> :t just
S>just :: a -> Maybe a
S>

S>Еще одну?

Я надеюсь ты сам то понимаешь, что демонстрацией только подобных примеров ты ещё больше подчёркиваешь мою правоту? )

_>>Вообще то сомнительная цитата (см. ниже), но если тебе очень хочется говорить именно в таких терминах, то никаких проблем нет — я могу сформулировать и в таких. И так правильная формулировка в таких терминах: функция my_equal_to ведёт себя как оператор равенства класса eq.

S>ты не договорил. Она ведет себя так же как eq — то есть по разному, в зависимости от типа. Иными словами — специальным образом (ad hoc).

А как там внутри реализован eq — это уже его дело, про которое my_equal_to никак не в курсе. Т.е. я могу поменять отдельно реализацию eq как мне угодно и соответственно изменится поведение my_equal_to, даже если она уже собрана в отдельный бинарный модуль. Не видишь ничего общего с apply? )

_>>Хы, вообще то cplusplus.com действительно давно протух и все знакомые с C++ программисты давным давно пользуются этим http://en.cppreference.com/w/cpp/string/char_traits/cmp (кстати можешь сравнить формулировку здесь и твою цитату) ресурсом. Но на нашу дискуссию данный факт никак не влияет, т.к. твои мелкие цепляния к формулировкам никак не меняют суть происходящего. )))

S>Ощутимой разницы в формулировке не нашел, наверное и cppreferencce.com тоже протух. Итого, получается что твоей точке зрения способствует лишь весьма своеобразная трактовка фразы "function may execute different code for each type of argument". Все остальное (хаскельвики, википедия, cpp ресурсы) — по-твоему тухлое. Но ты — весь в белом. И это тоже не меняет суть происходящего, а есть сама суть.

cplusplus.com протух не из-за этой фразы, а из-за несоответствия современному стандарту языка. Ну а насчёт попытки приписать мне мнение о тухлости остальных указанных ресурсов — это ты выдал очередное откровенное враньё.

P.S. В начале дискуссии ты ещё выдавал в каждом новом сообщение какие-то новые аргументы или тезисы. В данном же находится уже ровно ноль новой информации — одни попытки выехать на вранье или демагогии. Я конечно умею участвовать в дискуссии и на таком уровне, но обычно подобно начинает быстро навевать скуку...
Re[53]: «Собаку съел»
От: samius Япония http://sams-tricks.blogspot.com
Дата: 11.02.17 18:16
Оценка:
Здравствуйте, alex_public, Вы писали:

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


_>>>Я вижу смысл в таком разделение по той причине, что имеются языки с разным видом полиморфизма на уровне исходного кода и на уровне машинного. Т.е. очевидно параметрически полиморфная функция на уровне исходного кода, может иметь ad hoc реализацию (причём программист может об этом даже не знать, как часто бывает например в том же Хаскеле) на уровне машинных кодов.

S>>У исходного кода без execution model нет поведения, т.е. говорить не о чем, только об факте включения некоторого подтекста. Но при рассмотрении текста в совокупности с execution model, получается поведение и однозначная классификация полиморфизма по поведению.

_>Мне вот интересно, а ты способен вообще начать формулировать свои мысли с помощью технической терминологии, а не бытовой? А то понятие "поведение" же можно интерпретировать как угодно.

Мне вот интересно было, перейдешь ли ты на оценку способностей собеседника в явной форме? Благодарю что удовлетворил интерес.

_>Например вот возьму я две одинаковые функции, определённые отдельно (перегрузка) для float и для double и скажу что у них абсолютно одинаковое поведение (скажем "сложение чисел с плавающей точкой"). С твоей позиции это получается параметрический полиморфизм? )))

С твоей интерпретацией слова "абсолютно" я уже знаком. Чем больше находится опровержений, тем более "абсолютна" становится твоя мысль. На мой взгляд, то что ты говоришь что поведение сложения чисел с плавающей точкой абсолютно одинаковое — еще не делает его таким для разных представлений чисел. Но говорить ты можешь.

S>>Спасибо, но что-то я замечаю некоторую тавтологию. Ты вводишь полиморфизм исходного и полиморфизм машинного лишь для того что бы иметь возможность говорить о том что функции ведут себя одним образом на уровне исходников и другим на уровне машинных кодов. А зачем тебе такое — ты не поясняешь. Чего ради-то?


_>Я не ввожу разные полиморфизмы — классическое определение с безликим "код" вполне мне подходит. Я просто применяю его на двух отдельных уровнях размышления.

Так, что это тебе дало, кроме путаницы при общении и разногласии с источниками?

S>>Я просто уже не знаю, как тебе говорить о поведении. Я тебе говорю о поведении — ты мне об исходниках.


_>Потому что нет такого термина как поведение. Сформулируй свою мысль в технических терминах, а не так, чтобы его можно было интерпретировать как угодно, в зависимости от выгоды конкретной ситуации.

Ты же интерпретируешь. Я тебе уже писал, что именно подразумевают под поведением люди в научной среде. Но тебе все время хочется съехать то на поведение уровня текста, то на поведение уровня количества вызовов.

_>>>Ну т.е. получается что всё же исходников достаточно? ))) Или как? )

S>>В совокупности с execution model — наверняка.

_>Вот любишь ты использовать скользкие понятия. Вот скажи мне, например в случае Хаскеля в его "execution model" входит тот факт, что в языке есть только функции одного аругмента (а запись вроде как функции нескольких просто является упрощённой записью последовательности нескольких вызовов)? Или же там наоборот указано, что данные объявления последовательностей вызовов в реальности превращаются в классические функции многих аргументов? )

В стандарте языка указано лишь как записывается function application, и что оно левоассоциативно. Остальное — детали частной реализации, не имеющие значения с точки зрения поведения. Но имеющие с точки зрения оптимизации, если ты хочешь об этом услышать. Впрочем, это не повод тащить эти детали на уровень языка.

_>>>Т.е. ты тут хочешь сказать, что с твоей точки зрения вид полиморфизма функции apply нельзя определить без уточнения её параметров, правильно?

S>>Не правильно. apply не вызывает никакого специального кода прямо или косвенно до тех пор, пока ей не подадут явно через параметр такой код прямо или косвенно.

_>И? ) Так какой тогда полиморфизм у apply? )

параметрический

S>>В то время, как equal_to и my_equal_to просто неотделимы от выполнения специального кода для каждого типа.


_>Ну вообще то это не так даже для equal_to, т.к. мы можем определить единый для всех типов оператор равенства (понятно что смысла в подобном мало, но сам факт подобной возможности однозначен).

Определить — то мы можем, но и поведение изменится.
_>А уж для my_equal_to это на 100% не верно, потому как в ней происходит вполне себе параметрически полиморфный вызов оператора равенства для типа eq и всё — что там происходит внутри этого оператора (разный код для разных типов или нет) my_equal_to не касается.
Это твое частное мнение, которое нечем подкрепить. Оно расходится, как минимум (кроме определений), с работами Wadler-а по введению классов типа, расходится с методами классификации, предлагаемыми хаскельвики.

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

S>>Но ты в упор не хочешь замечать что под фразу "function may execute different code for each type of argument" подходят функции, которые явно вызывают перегрузки функций, или ведут себя в точности как соответствующие перегрузки для каждого типа. Хорошо, только я бы не стал называть такую точку зрения "неплохо совместимой" с этими цитатами. Но ты можешь продолжать называть ее так, несмотря на мое мнение. Вобщем, нашли точку где наши знания английского явно расходятся (да и русского тоже, если фразу перевести).

_>Ну да, интерпретировать "исполняют разный код для разных типов" в "ведут себя в точности как соответствующие перегрузки" — это очень забавно. )))

Это ты так интерпретировал? Я такого не писал.

S>>
S>>Prelude> just a = Just a
S>>Prelude> :t just
S>>just :: a -> Maybe a
S>>

S>>Еще одну?

_>Я надеюсь ты сам то понимаешь, что демонстрацией только подобных примеров ты ещё больше подчёркиваешь мою правоту? )

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

_>>>Вообще то сомнительная цитата (см. ниже), но если тебе очень хочется говорить именно в таких терминах, то никаких проблем нет — я могу сформулировать и в таких. И так правильная формулировка в таких терминах: функция my_equal_to ведёт себя как оператор равенства класса eq.

S>>ты не договорил. Она ведет себя так же как eq — то есть по разному, в зависимости от типа. Иными словами — специальным образом (ad hoc).

_>А как там внутри реализован eq — это уже его дело, про которое my_equal_to никак не в курсе. Т.е. я могу поменять отдельно реализацию eq как мне угодно и соответственно изменится поведение my_equal_to, даже если она уже собрана в отдельный бинарный модуль. Не видишь ничего общего с apply? )

Пока my_equal_to сравнивает значения разных типов специальным образом в соответствии с типом — ничего общего с apply у нее нет. Если my_equal_to начинает сравнивать значения разных типов универсальным образом, то у нее нет ничего общего со сравнением типов через оператор == с соответствующим поведением.

_>>>Хы, вообще то cplusplus.com действительно давно протух и все знакомые с C++ программисты давным давно пользуются этим http://en.cppreference.com/w/cpp/string/char_traits/cmp (кстати можешь сравнить формулировку здесь и твою цитату) ресурсом. Но на нашу дискуссию данный факт никак не влияет, т.к. твои мелкие цепляния к формулировкам никак не меняют суть происходящего. )))

S>>Ощутимой разницы в формулировке не нашел, наверное и cppreferencce.com тоже протух. Итого, получается что твоей точке зрения способствует лишь весьма своеобразная трактовка фразы "function may execute different code for each type of argument". Все остальное (хаскельвики, википедия, cpp ресурсы) — по-твоему тухлое. Но ты — весь в белом. И это тоже не меняет суть происходящего, а есть сама суть.

_>cplusplus.com протух не из-за этой фразы, а из-за несоответствия современному стандарту языка. Ну а насчёт попытки приписать мне мнение о тухлости остальных указанных ресурсов — это ты выдал очередное откровенное враньё.

Гипербола. Ты вроде бы написал что хаскельвики для тебя не авторитет...

_>P.S. В начале дискуссии ты ещё выдавал в каждом новом сообщение какие-то новые аргументы или тезисы. В данном же находится уже ровно ноль новой информации — одни попытки выехать на вранье или демагогии. Я конечно умею участвовать в дискуссии и на таком уровне, но обычно подобно начинает быстро навевать скуку...


Извини, я не подписывался удивлять тебя в каждом посте новым тезисом. И бубнить одно и то же. Навевает скуку — давай расстанемся. Я ничего не теряю.
Re[7]: IEquatable<T>
От: vdimas Россия  
Дата: 13.02.17 02:22
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>Твоё утверждение «Никак он не вызывается. x.Equals(y) — это метод базового Object» наглядно свидетельствует о том, что ты совершенно не понимаешь происходящего. Вопрос вполне можно рекомендовать к включению в собеседование на должность джуниора, чтобы сразу отсеевать тех, кто не обладает минимальной компетенцией.


Ты уныл, бо недостаточно умён. Ситуация была простая — ты мне дал некую ссылку, я по ней прошел, увидел сниппет кода и сообщил, что вызывается метод базового Object. После этого ты 4 поста тормозишь как стадо Камазов, хотя я тебе уже прямо сообщил, что и как вышло.

Как ты вообще работаешь по специальности с такой недогадливостью? Как ты задачи-то решаешь, которые сложнее 2+2? И о каком, о боже, СОБЕСЕДОВАНИИ ты можешь вести речь, если ты не понимаешь и половины того, что тебе говорят? Кого ты там собеседовать собрался с такими навыками информационного метаболизма? Какой нафик джуниора, да еще за твоими "рекомендациями"??? О чем ты??? Мы же еще о программировании говорим, верно? Можно не обладать неким фактическим материалом, но на собеседовании обязательно проверяется еще способность мыслить, способность решать задачи. Знай ты хоть наизусть некий несложный фактический материал — пофиг, программист из тебя будет аховый, если ты уже столько раз спалился суровой несообразительностью.
Re[8]: IEquatable<T>
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.02.17 04:31
Оценка:
Здравствуйте, vdimas, Вы писали:

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


Q>>Твоё утверждение «Никак он не вызывается. x.Equals(y) — это метод базового Object» наглядно свидетельствует о том, что ты совершенно не понимаешь происходящего. Вопрос вполне можно рекомендовать к включению в собеседование на должность джуниора, чтобы сразу отсеевать тех, кто не обладает минимальной компетенцией.


V>Ты уныл, бо недостаточно умён. Ситуация была простая — ты мне дал некую ссылку, я по ней прошел, увидел сниппет кода и сообщил, что вызывается метод базового Object. После этого ты 4 поста тормозишь как стадо Камазов, хотя я тебе уже прямо сообщил, что и как вышло.

Так это все-таки "извини, был неправ, невнимателен, так вышло"?

V>Как ты вообще работаешь по специальности с такой недогадливостью? Как ты задачи-то решаешь, которые сложнее 2+2? И о каком, о боже, СОБЕСЕДОВАНИИ ты можешь вести речь, если ты не понимаешь и половины того, что тебе говорят? Кого ты там собеседовать собрался с такими навыками информационного метаболизма? Какой нафик джуниора, да еще за твоими "рекомендациями"??? О чем ты??? Мы же еще о программировании говорим, верно? Можно не обладать неким фактическим материалом, но на собеседовании обязательно проверяется еще способность мыслить, способность решать задачи. Знай ты хоть наизусть некий несложный фактический материал — пофиг, программист из тебя будет аховый, если ты уже столько раз спалился суровой несообразительностью.

За такими посылами действительно сложно сообразить, что это " "
Re[45]: benchmark
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 13.02.17 07:16
Оценка:
Здравствуйте, alex_public, Вы писали:

_>>>Не следует путать final (кстати тоже есть в C++, как отдельная сущность) и не виртуальные функции. В отличие от последних final полностью блокирует одно из ключевых преимуществ ООП подхода — расширяемость и кастомизируемость через наследование.

N>>Я не путаю. Задача исключить переопределение в потомке им обеспечивается, а подобные философии тут не интересны.
N>>Тем более что одна из задач final — исключить как раз это "ключевое преимущество" в конкретном месте.
_>С этой задачей то final конечно без проблем справляется. Только вот ты похоже забыл, что в данной дискуссии обсуждаются оптимизации и соответственно задача совсем другая стоит. А именно: обеспечить наиболее эффективный вызов функций, причём желательно не вводя при этом никаких ограничений на код. И вот как раз со второй частью у final проблемы. )

Ну так и у C++ в этом проблемы. Не написал virtual — оп-па, ввёл ограничение. Причём, сюрприз, сам того не зная! (пока не выработал привычку замечать это на каждом новом добавлении)
И вся разница — что одна молча даёт, а другая дразнится. ©

_>>> Так что если в своём коде ты вполне можешь позволить себе применять данную возможность, то у скажем авторов библиотек ситуация намного печальнее.

N>>Шарповцы в большом количестве стандартных классов размахивают своим sealed направо и налево. Расскажи им про эту печаль.
_>Не знаю где они там и чем размахивают, но в любом случае сильно сомневаюсь, что sealed там активно применяется именно для оптимизаций. Скорее для архитектурных целей, так же как и final в C++.

А тут фиг отделиш одно от другого. "Архитектурные цели" в смысле не допустить изменения базового класса (и получить какие-то гарантии от этого, например, возможностью JIT что-то инлайнить не занимаясь поиском по потомкам) это то же самое, что в твоём случае возможность сэкономить на вызове по VMT. Ну да, есть особые случаи — когда переопределение может сломать рантайм в целом — но таких исключений немного, насколько я видел.

N>>В C# не щупал, но если они не воспользуются этим при немедленном стартовом JIT, я удивлюсь. Хотя что-то навскидку помню — показывали выход IL, где он вызывал явно, а где через VMT. Так что тоже должно работать.

_>В этой темке народ тестировал — по их словам не работает такая оптимизация в C#.

Хм, попадётся снова — заброшу сюда пример. Может, ещё от конкретного рантайма зависит.
The God is real, unless declared integer.
Re[9]: IEquatable<T>
От: vdimas Россия  
Дата: 13.02.17 11:34
Оценка:
Здравствуйте, samius, Вы писали:

V>>Ситуация была простая — ты мне дал некую ссылку, я по ней прошел, увидел сниппет кода и сообщил, что вызывается метод базового Object. После этого ты 4 поста тормозишь как стадо Камазов, хотя я тебе уже прямо сообщил, что и как вышло.

S>Так это все-таки "извини, был неправ, невнимателен, так вышло"?

А почему я был не прав? ))
Мне кидают ссылку с простынёй кода.
Не объясняют даже ЗАЧЕМ.
Т.е. в оппонента летит ссылка БЕЗ внятной аргументации.

Я не прав был, что не изучил её (простыню) всю? ))

Вместо такого фокуса коллега мог назвать конкретный метод конкретного типа и никаких ссылок не надо — кому попервой и даже любопытно, пусть смотрит сам. А остальным, кто еще 12-15 лет назад это всё уже прожевал и выкакал, сорри, тому банально не любопытно глазеть на подобный код.

Дотнет на сегодня — это уже довольно древняя технология, об этом надо таки помнить. Оно ведь даже скорее раздражает, когда собеседник пытается спорить и аргументировать вот на таком уровне.

В общем, озвуч он членораздельно свой аргумент, и я сходу бы ему и ответил, почему его аргумент кривой, косой и не канает. Потому что, с начала всех начал, его пример НЕ является примером:
1. там в любом случае происходит вызов метода интерфейса;
2. дефолтный компаратор порождается через рефлексию; особенно весело сие после пространных рассуждений коллеги о "безопасной компиляции";
3. коллега пытался аргументировать об одинаковой работе для случая value-type и ref-type, но приводит такой пример, где методы типа Т не вызываются вовсе, а вызываются методы исключительно ref-типа IComparer<T> (в теле генерик-метода);

И о последнем так же уже было уже сказано ему же рядом более одного раза. И даже было сказано, как это можно было бы исправить (в каких-нить своих коллекциях, например). Однако же, однако же... Это такая разновидность слепоты? Или гипертрофированная инерционность? Что это вообще было? ))

Этого коллеге показалось мало и его стало заносить далее: " ты даже на джуниора не потянул бы, ты совершенно не понимаешь происходящего".
Мамая мия.

В итоге, коллега заслуженно был подвергнут нещадной обструкции.
Причем, весьма мягкой, ИМХО, учитывая происходящее целиком. ))

============
Хотя, если упустить весь рисунок развития ситуации, согласен, моя реакция может показаться странной. Там надо на десяток постов вверх подниматься и смотреть на картинку целиком.

=========
Ну вот я тебе пишу тут, ОК.
Много.
По одной простой причине — ты обычно сходу понимаешь, что тебе пишут. ))
Смотри как мало надо собеседнику для счастья.
Отредактировано 13.02.2017 11:36 vdimas . Предыдущая версия .
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.