Re[25]: Рефакторинг
От: Evgeny.Panasyuk Россия  
Дата: 10.01.17 11:53
Оценка: 1 (1) :)
Здравствуйте, vdimas, Вы писали:

V>Собсно, вообще таких алгоритмов мало, которые можно выразить в дотнете для value и ref-типов в генериках и они будут корректно работать в обоих случаях. Я одно время на этом собаку съел, в поисках классов таких алгоритмов, которые, таки, работают в обоих случаях и в попытках сформулировать ограничения на такие алгоритмы.


Местами вообще в алгоритмы закладывают
Автор: Evgeny.Panasyuk
Дата: 23.03.16
разную семантику для value vs ref типов — вот уж где будет бесшовный рефакторинг при замене одного на другое
Re[36]: benchmark
От: Evgeny.Panasyuk Россия  
Дата: 10.01.17 12:46
Оценка:
Здравствуйте, lpd, Вы писали:

lpd>Я еще пока не успел разобраться в твоем тесте, но думаю, что дело в вызовах boost.


В каких? boost::accumulate вызывает std::accumulate.
boost::adaptors::indirected без проблем инлайнится, например:
.L152:
    mov    rcx, QWORD PTR [rax]
    add    rax, 8
    add    edx, DWORD PTR [rcx]
    cmp    rsi, rax
    jne    .L152

Ок, допустим ты на adaptors::indirected думаешь, но как тогда в твоей картине мира объясняется более чем стократное торможение на list<int>? — там никакого adaptors::indirected.

Ладно, вместо тысячи слов — встречайте её могущество копипаста без boost'а. Соотношения получились примерно те же самые
Отредактировано 11.01.2017 23:40 Evgeny.Panasyuk . Предыдущая версия . Еще …
Отредактировано 10.01.2017 12:55 Evgeny.Panasyuk . Предыдущая версия .
Без слов
От: Qbit86 Кипр
Дата: 10.01.17 12:51
Оценка:
https://github.com/dotnet/coreclr/.../EqualityComparer.cs:
using System;
using System.Collections.Generic;

internal class GenericEqualityComparer<T> : EqualityComparer<T> where T : IEquatable<T>
{
    public override bool Equals(T x, T y)
    {
        if (x != null)
        {
            if (y != null) return x.Equals(y);
            return false;
        }
        if (y != null) return false;
        return true;
    }

    public override int GetHashCode(T obj) => obj?.GetHashCode() ?? 0;

    // ...
}


Q>>Пример был про то, как вызывается метод констрейнта у экземпляра типа


V>Никак он не вызывается.

V>x.Equals(y) — это метод базового Object



internal struct Foo : IEquatable<Foo>
{
    public bool Equals(Foo other)
    {
        Console.WriteLine("Equals(Foo other)");
        return true;
    }

    public override bool Equals(object obj)
    {
        Console.WriteLine("Equals(object obj)");
        return true;
    }

    public override int GetHashCode() => 0;
}

internal static class Program
{
    private static void Main()
    {
        var comparer = new GenericEqualityComparer<Foo>();
        var x = new Foo();
        var y = new Foo();
        var equal = comparer.Equals(x, y);
        Console.WriteLine(equal);
    }
}


V>Тут нечего далее обсуждать. Усё, припыли.


Глаза у меня добрые, но рубашка — смирительная!
Отредактировано 10.01.2017 13:35 Qbit86 . Предыдущая версия .
Re[37]: benchmark
От: lpd Черногория  
Дата: 10.01.17 13:27
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Ладно, вместо тысячи слов — встречайте её могущество копипаста без boost'а. Соотношения получились примерно те же самые


1) По твоему тесту:
Во-первых, как я понял, ты пытаешься измерить задержки из-за cache-miss с помощью listа. Думаю, что это не очень хороший подоход, т.к. элементы list могут быть расположены в памяти последовательно. В моем же тесте, я точно обращаюсь к элементам в случайном порядке.
Во-вторых, ты измеряешь производительность stl контейнеров, а не процессора.
2) По моему тесту:
В моем измерении тоже были ошибки: я компилировал без оптимизатора, а когда подключил оптимизатор он выкинул весь расчет. В конце поста я приведу для конкретности последний вариант своего кода.
Результаты изменились:
Последовательное сложение с индирекцией оказалось ровно в два раза медленне, чем с индирекцией. Это ожидаемо, т.к. выполняется две инструкции, вместо одной.
Сложение со случайным доступом(и вечным cache-miss) оказалось еще в два раза медленнее, чем с последовательным. Это обозначает верхнюю границу эффективности кэша при доступе к данным, и для меня интересно.
Предлагаю на этом результате остановиться, т.к. он меряет именно скорость процессора, а не скорость контейнеров stl. Кстати, только vector<int> оказался по скорости близок к массивам, а в остальных вариантах при одном, по сути, алгоритме твоя программа с stl, действительно, работает на порядки медленнее моей при одном размере массива(что удивило даже меня).

Относительно причин задержек Java/C# vs C++ думаю, что лишний код присущ JIT-компиляторам, и лишние индирекции часть этой проблемы. Однако, программируя на C++, очень редко есть смысл заботиться об индирекции, т.к. далеко не все функции в программе занимают значительное время. И алгоритм работы(особенно не относящийся к вычислительным) почти никогда не состоит из одной инструкции сложения чисел, поэтому обращения к памяти вносят меньший вклад во время выполнения, чем в этих синтетических тестах. Поэтому для меня лично кэш-миссы и индирекции недостаточная причина всегда использовать move-семантику для каждого вектора больших объектов(т.к. это слишком мелкая микрооптимизация, усложняющая код) и все же буду использовать указатели, а при тяжелых вычислениях я постараюсь обойтись без stl. Вообще, C++ быстр сам по себе и программа будет работать быстрее, чем C#/Java, в любом варианте.

Привожу мой тест в последнем варианте:
#include <iostream>
#include <chrono>
#include <stdlib.h>
using namespace std;

#define SIZE 4000*1000
int *array;
int *map1, *map2;
int test(int *map) 
{
        int sum = 0;
        for (int i=0; i<SIZE; i++)
                sum += array[map[i]];
        return sum;
}
int test0()
{
        int sum = 0;
        for (int i=0; i<SIZE; i++)
                sum += array[i];
        return sum;
}
int main()
{
        srand(time(0));
        array = new int[SIZE];
        map1 = new int[SIZE];
        for (int i=0;i<SIZE;i++) {
                map1[i] = i;
                array[i] = random();
        }
        map2 = new int[SIZE];
        for (int i=0;i<SIZE;i++)
                map2[i] = random()%SIZE;
        auto start0 = std::chrono::high_resolution_clock::now();
        int r = test0();
        auto finish0 = std::chrono::high_resolution_clock::now();
        cout << r << ":" <<std::chrono::duration_cast<std::chrono::nanoseconds>(finish0-start0).count() << "ns\n";

        auto start1 = std::chrono::high_resolution_clock::now();
        r = test(map1);
        auto finish1 = std::chrono::high_resolution_clock::now();
        cout << r << ":" << std::chrono::duration_cast<std::chrono::nanoseconds>(finish1-start1).count() << "ns\n";

        auto start2 = std::chrono::high_resolution_clock::now();
        r = test(map2);
        auto finish2 = std::chrono::high_resolution_clock::now();
        cout << r << ":" << std::chrono::duration_cast<std::chrono::nanoseconds>(finish2-start2).count() << "ns\n";
}
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Отредактировано 10.01.2017 13:34 lpd . Предыдущая версия . Еще …
Отредактировано 10.01.2017 13:33 lpd . Предыдущая версия .
Re[32]: «Собаку съел»
От: vdimas Россия  
Дата: 10.01.17 17:08
Оценка:
Здравствуйте, Serginio1, Вы писали:

S> Это же все можно делать и в C# это же Func<X,Y>


Ну, дык, статически диспетчеризируемую полиморфную операцию сравнения не сделать.
Только динамически через экземпляр IComparer<T> или через ручной copy&paste с целью ad-hoc полиморфизма.

Причем, там же рядом я писал:

Понятно, что x => x.Y выглядит тривиально, это был лишь пример. В общем случае "оно" может быть не тривиальным, т.к. именно под нетривиальные объемы кода пишут те самые шаблоны "многоразового применения" — в этом их фишка.


Это всё к тому, что твой пример с copy&paste вот этого:
where(x => x > q)

в общем случае является плохой практикой.
Но язык позволяет только такую.

И да, как и в адрес Qbit86 я умудрился ответить на все вопросы намного раньше, чем их задали. ))
И ладно бы, тебе я копирую с соседней подветки, а вот означенному персонажу я заранее отвечал в этой же, предугадывая его т.н. "логику".
И всё-равно там отставание по фазе дважды случилось...
Re[26]: Рефакторинг
От: vdimas Россия  
Дата: 10.01.17 17:20
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Местами вообще в алгоритмы закладывают
Автор: Evgeny.Panasyuk
Дата: 23.03.16
разную семантику для value vs ref типов — вот уж где будет бесшовный рефакторинг при замене одного на другое


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

И что характерно, что в терминах JIT-машинки управляемая ссылка на объект и управляемая ссылка на поле объекта или ref/out-параметр передаваемой через аргументы структуры — всё это обслуживается одинаково, т.е. под это генерится идентичный код, а GC затем прекрасно умеет отличить ref-ссылку на поле объекта в куче от такой же ссылки на экземпляр на стеке. Но, в терминах языка C#, ref/out value-type и переменная ссылочного ref-типа это РАЗНЫЕ типы ссылок, о как! ))

Т.е., там где в С++ алгоритму глубоко до фени, где создан объект (на куче, на стеке или в виде поля другого объекта), в дотнете в этом же месте есть исскуственно введеная непреодолимая разница на уровне типов. А разница семантики генериков для value-типов и для ref-типов, это как разница м/у указателем на тип и самим типом, т.е. разница, казалось бы, катастрофическая. Но тут ровно наоборот — код при этом должен "выглядеть" одинаково, ы-ы-ы много раз. ))
Re: Без слов
От: vdimas Россия  
Дата: 10.01.17 17:23
Оценка:
Здравствуйте, Qbit86, Вы писали:

Q>
using System;
Q>using System.Collections.Generic;

Q>internal class GenericEqualityComparer<T> : EqualityComparer<T> where T : IEquatable<T>
Q>{
Q>    public override bool Equals(T x, T y)
Q>    {
Q>        if (x != null)
Q>        {
Q>            if (y != null) return x.Equals(y);
Q>            return false;
Q>        }
Q>        if (y != null) return false;
Q>        return true;
Q>    }

Q>    public override int GetHashCode(T obj) => obj?.GetHashCode() ?? 0;

Q>    // ...
Q>}


Ну и чего ж этой реализации не хватило на все случаи?

Что не так-то?
Что именно не удалось выразить через "параметрический полиморфизм"?


V>>Тут нечего далее обсуждать. Усё, припыли.


[Картинка скипнута]

template<typename T>
bool is_equal(const T * x, const T * y) {
  if(x)
    return y ? *x == *y : false;  

  return !y;
}

template<typename T>
bool is_equal(const T & x, const T & y) {
  return x == y;  
}


Вот и всех делов на все случаи жизни.

Дарю.
Отредактировано 10.01.2017 17:39 vdimas . Предыдущая версия .
Re[2]: x.Equals(y)
От: Qbit86 Кипр
Дата: 10.01.17 21:37
Оценка: :)))
Здравствуйте, vdimas, Вы писали:

V>Что не так-то?


Не так вот эта чушь: «Никак он не вызывается. x.Equals(y) — это метод базового Object», в ответ на «Пример был про то, как вызывается метод констрейнта у экземпляра типа».

Приведённый код самодостаточен, его можно скопировать в IDE и запустить: http://ideone.com/9tlRqT
Любой может проверить, что вызывается, конечно, метод, реализующий интерфейс `IEquatable<T>`, а не «метод базового Object».

«
Автор: vdimas
Дата: 02.01.17
Значит, такое владение предметом.» Это ведь не голословное утверждение, а результат прямой и непосредственной проверки твоего заявления.

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

Этот глумильщик сломался, несите следующего.
Глаза у меня добрые, но рубашка — смирительная!
Re[3]: x.Equals(y)
От: vdimas Россия  
Дата: 10.01.17 22:12
Оценка:
Здравствуйте, Qbit86, Вы писали:

V>>Что не так-то?

Q>Не так вот эта чушь: «Никак он не вызывается. x.Equals(y) — это метод базового Object», в ответ на «Пример был про то, как вызывается метод констрейнта у экземпляра типа».

У тебя по ссылке 4 места с x.Equals(y), например такое:
internal sealed class ObjectEqualityComparer<T>: EqualityComparer<T>
    {
        [Pure]
        public override bool Equals(T x, T y) {
            if (x != null) {
                if (y != null) return x.Equals(y);
                return false;
            }
            if (y != null) return false;
            return true;
        }


Q>Приведённый код самодостаточен, его можно скопировать в IDE и запустить


Ну запусти и убедись, вызывается метод класса Object.


Q>Ты хамишь и пытаешься самоутвердиться


На тебе самоутверждаться малость не спортивно.


Q>повторяя какую-то чушь, о том как ты что-то там предугадал, а оппонент не прочитал твои мысли.


Пока что ты банально написанное не можешь прочесть и дважды умудрился спросить меня о том, что я тебе уже заранее ответил.
Какие там в опу "мысли предугадать"...


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


Ты так и не показал моего непонимания. Ну вот я тебе дал снипет по твоей ссылке.
Выкручивайся.


Q>без знания которых нельзя пройти собеседование даже на джуниора.


Кисо обиделось?
А как же я тут тебе заранее написал:

Даже если у тебя будет констрейн where T : IBarable<T> — я уверен, ты сам сможешь доработать мой сниппет до такого сценария.


Ну вот и третья задержка по фазе.
Стабильность, признак мастерства?


Q>Этот глумильщик сломался, несите следующего.


А не, просто пафос. Следом будет очередное пффф. ))
Re[4]: x.Equals(y)
От: Qbit86 Кипр
Дата: 10.01.17 22:24
Оценка:
Здравствуйте, vdimas, Вы писали:

Q>>Не так вот эта чушь: «Никак он не вызывается. x.Equals(y) — это метод базового Object», в ответ на «Пример был про то, как вызывается метод констрейнта у экземпляра типа».


V>У тебя по ссылке 4 места с x.Equals(y), например такое:

V>
internal sealed class ObjectEqualityComparer<T>: EqualityComparer<T>


Не паясничай, речь шла
Автор: Qbit86
Дата: 10.01.17
про `GenericEqualityComparer<T>`:

Навскидку, есть такой класс:

internal class GenericEqualityComparer<T>: EqualityComparer<T> where T: IEquatable<T>

Глаза у меня добрые, но рубашка — смирительная!
Re[5]: x.Equals(y)
От: vdimas Россия  
Дата: 11.01.17 02:57
Оценка: -1
Здравствуйте, Qbit86, Вы писали:

V>>У тебя по ссылке 4 места с x.Equals(y), например такое:

V>>
internal sealed class ObjectEqualityComparer<T>: EqualityComparer<T>

Q>Не паясничай, речь шла
Автор: Qbit86
Дата: 10.01.17
про `GenericEqualityComparer<T>`:


Который не умеет вызывать operator==? ))

А почему бы мне не было дать тебе понять, что ты явно поторопился рассуждать о каких-то там юниорах, после вот этого:

Даже если у тебя будет констрейн where T : IBarable<T> — я уверен, ты сам сможешь доработать мой сниппет до такого сценария.


Т.е., следующий твой шаг в рассуждениях от T к ISomeInterface<T> был слишком очевидным на тот момент, что я заранее попытался тебя попросить не рвать жилы в эту сторону, бо там там преимуществ перед С++ тоже не найдёшь, а, ровно наоборот — обнять и плакать. ))

Ан нет, до тебя даже такой толстый намёк не дошёл.


Q>

Навскидку, есть такой класс:
Q>

internal class  GenericEqualityComparer<T>: EqualityComparer<T> where T: IEquatable<T>


Ну и?
Ты ведь вызвался оспорить вот это:

Собсно, вообще таких алгоритмов мало, которые можно выразить в дотнете для value и ref-типов в генериках и они будут корректно работать в обоих случаях.

Ну как, получилось?

Разве ты еще не увидел, что твой пример был неудачный? Что сам вот этот код — это workaround вокруг тривиальных в других языках вещей?
Что это не целевой ни разу код, а тупо костыль, "восполнение пробела"?
Что базовые типы засоряются реализацией тонны методов прямо в метаинформации и в байт-коде?
И что выделенное ключевое слово — это ошибка дизайна?
Что надо было дать некий struct ValueTypeComparer<T> как минимум, потому что иначе ЛЮБОЕ сравнение, сцуко, всё-равно будет происходить через метод интерфейса, т.е. никакой нафик параметрический полиморфизм толком не будет работать — будет голая динамика плюс эдакий синтаксический сахар.

Что даже указанный тобой "типизированный" вызов x.Equals(y) происходит внутри генерик-метода, реализующего интерфейс? (что ты скромно делаешь вид, что не замечаешь или подзабыл, угу)

Ну и возвращаясь к нашим баранам. Вот, если быть честным с самим собой (забыть на минуту о запале форумного боя), ты что, ДЕЙСТВИТЕЛЬНО не согласен с процитированным (последнее на жёлтеньком)?

А то ж, если будешь продолжать упираться, то уже мне придется шутить о соответствии хотя бы джуниору, только, в отличие от, с полным основанием-то. ))

Не хочешь на досуге помедитировать над вот этой сладкой парочкой, кста? Очень рекомендую к ознакомлению. Это именно то, как решаются реальные проблемы (С) при наличии, казалось бы, рекламируемого тобой якобы "параметрического полиморфизма" в C#. Весь код по ссылке именно таков как раз от того, что дотнетный якобы "параметрический полиморфизм" не в состоянии разресолвится статически, исключив динамику интерфейсных вызовов, потому что не реализует статически даже полиморфизм 1-го ранга, в отличие от того же Хаскеля, который ровно в этих же сценариях ресолвит всё статически. В общем, добро пожаловать в реальный мир, Нео.
Re[4]: x.Equals(y)
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 11.01.17 07:03
Оценка: 1 (1) :)
Здравствуйте, vdimas, Вы писали:

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


V>>>Что не так-то?

Q>>Не так вот эта чушь: «Никак он не вызывается. x.Equals(y) — это метод базового Object», в ответ на «Пример был про то, как вызывается метод констрейнта у экземпляра типа».

V>У тебя по ссылке 4 места с x.Equals(y), например такое:

V>
V>internal sealed class ObjectEqualityComparer<T>: EqualityComparer<T>
V>    {
V>        [Pure]
V>        public override bool Equals(T x, T y) {
V>            if (x != null) {
V>                if (y != null) return x.Equals(y);
V>                return false;
V>            }
V>            if (y != null) return false;
V>            return true;
V>        }
V>


Q>>Приведённый код самодостаточен, его можно скопировать в IDE и запустить


V>Ну запусти и убедись, вызывается метод класса Object.



Метод IEquatable&lt;T&gt;.Equals(T)


 public bool Equals(Person other)
   {
      if (other == null)
         return false;

      if (this.uniqueSsn == other.uniqueSsn)
         return true;
      else
         return false;
   }

   public override bool Equals(Object obj)
   {
      if (obj == null)
         return false;

      Person personObj = obj as Person;
      if (personObj == null)
         return false;
      else
         return Equals(personObj);
   }


Будет вызываться метод Equals интерфейса IEquatable.

Иначе бы в public override bool Equals(Object obj) была бы бесконечная рекурсия.

Все по приоритетам. Я даже отдельно делал свой сортировщик по приоритетам для ref параметров при вызове через Reflection из 1С

Приоритет вызова перегруженных методов
Автор: Serginio1
Дата: 09.06.16
и солнце б утром не вставало, когда бы не было меня
Отредактировано 11.01.2017 8:40 Serginio1 . Предыдущая версия . Еще …
Отредактировано 11.01.2017 7:18 Serginio1 . Предыдущая версия .
Отредактировано 11.01.2017 7:05 Serginio1 . Предыдущая версия .
Отредактировано 11.01.2017 7:04 Serginio1 . Предыдущая версия .
Re[6]: IEquatable<T>
От: Qbit86 Кипр
Дата: 11.01.17 08:32
Оценка: -1 :)
Здравствуйте, vdimas, Вы писали:

Q>>Не паясничай, речь шла
Автор: Qbit86
Дата: 10.01.17
про `GenericEqualityComparer<T>`:

V>Который не умеет вызывать operator==? ))

А зачем его вызывать? Алгоритмы и коллекции стандартной библиотеки работают через компараторы, они не используют `operator ==`. Ты и этого не знал? Это легко проверить: для кастомного класса или структуры определи `operator ==` бросающим исключение:
using System;
using System.Collections.Generic;

internal struct /* or sealed class */ IntWrapper : IEquatable<IntWrapper>
{
    public IntWrapper(int i)
    {
        Value = i;
    }

    public int Value { get; }

    public bool Equals(IntWrapper other) => Value == other.Value;

    public override int GetHashCode() => Value.GetHashCode();

    public override bool Equals(object obj) { throw new NotSupportedException(); }

    public static bool operator ==(IntWrapper left, IntWrapper right) { throw new NotSupportedException(); }

    public static bool operator !=(IntWrapper left, IntWrapper right) { throw new NotSupportedException(); }
}

internal static partial class Program
{
    private static void Main()
    {
        var d = new Dictionary<IntWrapper, string>
        {
            { new IntWrapper(42), "Hello" },
            { new IntWrapper(1729), "World" },
        };

        var s = d[new IntWrapper(1729)];
        Console.WriteLine(s);
    }
}

Заодно убедишься, что `bool Equals(object obj) { throw new NotSupportedException(); }` тоже не вызывается.

V>Т.е., следующий твой шаг в рассуждениях от T к ISomeInterface<T> был слишком очевидным на тот момент... Ан нет, до тебя даже такой толстый намёк не дошёл. :xz:


Всем очевидно, что приводить аргументы в защиту твоей позиции — это твоя забота, а не оппонента. Если уж предугадываешь «слишком очевидные» шаги — продолжай это делать. Расписывай дальше, какими хаками обмазываться в плюсах и что к чему кастить, если в функцию передаётся не `T *`, а `std::vector<T>`, `std::function<T()>`, `std::function<void(T)>` и так далее.

V>Ты ведь вызвался оспорить вот это:

V>

V>Собсно, вообще таких алгоритмов мало, которые можно выразить в дотнете для value и ref-типов в генериках и они будут корректно работать в обоих случаях.

V>Ну как, получилось? :facepalm:

Конечно, пример с `IEquotable<T>` это наглядно показывает. В этом примере http://ideone.com/9tlRqT сделай Foo классом, а не структурой — всё будет «корректно работать в обоих случаях».

V>Разве ты еще не увидел, что твой пример был неудачный?

V>Что надо было дать некий struct ValueTypeComparer<T>

Ты просто не понял примера. Он был не про компарер и его использование. А про использование внутри него `IEquatable<T>`: не через `...some-method...(IEquatable<T> x, IEquatable<T> y)`, а через `...some-method...(T x, T y) ... where T : IEquatable<T>`:
public interface IEquatable<T>
{
    bool Equals(T other);
}

internal ...some-class...<T> ... where T : IEquatable<T>
{
    public override bool ...some-method...(T x, T y)
    {
        if (x != null)
        {
            if (y != null) return x.Equals(y);
            return false;
        }
        if (y != null) return false;
        return true;
    }

    ///...
}


V>Что даже указанный тобой "типизированный" вызов x.Equals(y) происходит внутри генерик-метода, реализующего интерфейс? (что ты скромно делаешь вид, что не замечаешь или подзабыл, угу)


В примере это вообще не важно, вызывающий «генерик-метод» может ничего не реализовывать, а быть сам по себе. Тут важно, что некий алгоритм выражается не напрямую через `IEquatable<T>`, а выражается в терминах `T : IEquatable<T>`, что позволяет передавать ему структуры без боксинга.

V>Ну и возвращаясь к нашим баранам. Вот, если быть честным с самим собой (забыть на минуту о запале форумного боя), ты что, ДЕЙСТВИТЕЛЬНО не согласен с процитированным (последнее на жёлтеньком)?


Да, расскажи, что помешает в этом примере http://ideone.com/9tlRqT сделать `Foo` не структурой а классом?

V>А то ж, если будешь продолжать упираться, то уже мне придется шутить о соответствии хотя бы джуниору, только, в отличие от, с полным основанием-то. ))


Твоё утверждение «Никак он не вызывается. x.Equals(y) — это метод базового Object» наглядно свидетельствует о том, что ты совершенно не понимаешь происходящего. Вопрос вполне можно рекомендовать к включению в собеседование на должность джуниора, чтобы сразу отсеевать тех, кто не обладает минимальной компетенцией.
Глаза у меня добрые, но рубашка — смирительная!
Re[24]: Visual C# vs C++. Надо сравнить перспективы.
От: alex_public  
Дата: 11.01.17 18:54
Оценка:
Здравствуйте, itslave, Вы писали:

_>>Нуу не стоит путать базовые принципы и недоработку реализации библиотечной функции под одной из платформ. )

I>Ну знаешь ли, и .NET тоже тогда кроссплатформенный. В базовых принципах. Ога, с недоработками реализации библиотечных функций одной из платформ.

Нуу смотри. Понятно, что сами языки в большинстве своём (не трогаем Ассемблер и т.п.) не зависят от платформы. Соответственно реальная кроссплатформенность определяется наличием компиляторов и стандартных библиотек под нужные платформы.

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

В случае C# мы просто имеем отсутствие этих самых библиотек для всех платформ кроме винды.

На мой взгляд это весьма разный уровень кроссплатформенности. )))
Re[25]: Visual C# vs C++. Надо сравнить перспективы.
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 11.01.17 19:24
Оценка:
Здравствуйте, alex_public, Вы писали:



_>В случае C# мы просто имеем отсутствие этих самых библиотек для всех платформ кроме винды.

А как же .Net Core?
и солнце б утром не вставало, когда бы не было меня
Re[26]: Visual C# vs C++. Надо сравнить перспективы.
От: TK Лес кывт.рф
Дата: 11.01.17 20:06
Оценка:
Здравствуйте, Serginio1, Вы писали:

_>>В случае C# мы просто имеем отсутствие этих самых библиотек для всех платформ кроме винды.

S>А как же .Net Core?

А ее даже под виндой испрльзовать стремно. Кстати, что там с поддежкой winxp или iot девайсов?
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[26]: Visual C# vs C++. Надо сравнить перспективы.
От: AlexRK  
Дата: 11.01.17 20:15
Оценка: +1
Здравствуйте, Serginio1, Вы писали:

_>>В случае C# мы просто имеем отсутствие этих самых библиотек для всех платформ кроме винды.

S>А как же .Net Core?

Хосспади, вы про этот долбаный великолепный .Net Core пишете в каждом посте.
Нет его по факту нигде, и не факт, что вообще будет. А если что-то и будет, то по производительности все равно будет хуже, чем С++.
Re[38]: benchmark
От: alex_public  
Дата: 11.01.17 20:16
Оценка:
Здравствуйте, lpd, Вы писали:

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




lpd>Последовательное сложение с индирекцией оказалось ровно в два раза медленне, чем с индирекцией. Это ожидаемо, т.к. выполняется две инструкции, вместо одной.


А какие у тебя опции оптимизации? Надеюсь включена автовекторизация? )

lpd>Сложение со случайным доступом(и вечным cache-miss) оказалось еще в два раза медленнее, чем с последовательным. Это обозначает верхнюю границу эффективности кэша при доступе к данным, и для меня интересно.


Ну так "в два раза медленнее" — это вроде вполне не плохой результат, не так ли? )

lpd>Относительно причин задержек Java/C# vs C++ думаю, что лишний код присущ JIT-компиляторам, и лишние индирекции часть этой проблемы.


Причины медленности Java и C# можно принципиально разделись на два типа:

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

2. Принципиальные архитектурные особенности. Такие как ориентация на ссылочные данные (я уже не говорю про так называемый "боксинг"), приводящие к той самой косвенности. Принудительные виртуальные функции. Убогая и никчемная интроспекция времени выполнения (рефлексия), вместо эффективной интроспекции времени компиляции (как например в языке D). И ещё множество подобных, но более узкоспециализированных нюансов, общим для которых является то, что их всех нельзя исправить не переделав платформу с нуля. Точнее в Java существует некий механизм (специальный оптимизатор работающий внутри JVM и изменяющий исполнение кода на основание наблюдения за его предыдущими исполнениями) под названием escape-анализ, который пытается частично исправлять ситуацию с излишней косвенностью (перемещая некоторые данные из кучи в стек) и виртуальными функциями (делая вместо виртуального вызова инлайнинг кода конкретного потомка), но он нормально срабатывает только для некоторых редких случаев и то вероятностно (в зависимости от обрабатываемых данных). Так что в целом можно сказать, что указанные проблемы являются принципиально неисправимыми.

Какой из этих типов тормозов вносит больший вклад зависит конечно же от конкретного кода. Но я сомневаюсь, что в большинстве случаев главной причиной является тип1 (как по сути утверждал тут ты).

lpd>Однако, программируя на C++, очень редко есть смысл заботиться об индирекции, т.к. далеко не все функции в программе занимают значительное время.


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

lpd>Вообще, C++ быстр сам по себе и программа будет работать быстрее, чем C#/Java, в любом варианте.


Это не так. Смотри хотя бы предыдущий абзац.
Re[39]: benchmark
От: lpd Черногория  
Дата: 11.01.17 20:44
Оценка:
Здравствуйте, alex_public, Вы писали:

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


lpd>>Сложение со случайным доступом(и вечным cache-miss) оказалось еще в два раза медленнее, чем с последовательным. Это обозначает верхнюю границу эффективности кэша при доступе к данным, и для меня интересно.


_>Ну так "в два раза медленнее" — это вроде вполне не плохой результат, не так ли? )


Неплохой, однако в типичной серверной/десктопной/системной программе на C++(мы вроде не говорим на вычислениях) редко встречается последовательный доступ к большим векторам, да еще с минимальной обработкой. Ясно, что в редких случаях, вроде обработки запроса из кэша баз данных(например) доступ последовательный, но и там temportal кэширование важнее, чем spatial. Поэтому я бы не сказал, что однозначно всегда лучше хранить в векторе объекты, чем указатели. Т.к. обычно это вопрос архитектуры, или избежания копирования, а не оптимизации кэша. Хотя, случаи разные, — это понятно.

lpd>>Относительно причин задержек Java/C# vs C++ думаю, что лишний код присущ JIT-компиляторам, и лишние индирекции часть этой проблемы.


_>Причины медленности Java и C# можно принципиально разделись на два типа:


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


Я не исследовал JVM, но могу предположить, что байт код отличается от внутреннего представления программы компилятором, поэтому он вносит дополнительные сущности, которые потом сложно соптимизировать. Это всего лишь мое предположение. Однако, я думаю, что низкая производительность присуща любому языку, преобразуемому в промежуточный байт-код. Иначе давно бы Java, C# или другой подобный язык догнал по скорости C++(правда, я все равно считал бы, что байт-код по сути является не нужным усложнением).
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re[38]: benchmark
От: pilgrim_ Россия  
Дата: 11.01.17 21:19
Оценка:
Здравствуйте, lpd, Вы писали:

lpd>Сложение со случайным доступом(и вечным cache-miss) оказалось еще в два раза медленнее, чем с последовательным. Это обозначает верхнюю границу эффективности кэша при доступе к данным, и для меня интересно.


Вероятно сильно зависит от железа (проц? размер кэшей ?), но разница может доходить и до порядка:

http://melpon.org/wandbox/permlink/pMNslZwV7Q4oiMa9
  выхлоп
-1391154096:3080897ns
-1391154096:9087302ns
Diff: 200%
-179497116:192376237ns
Diff: 2100%


http://cpp.sh/6mwku
  выхлоп
-28677284:3061263ns
-28677284:3978124ns
Diff: 100%
-1050604135:33137029ns
Diff: 800%
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.