Здравствуйте, Sinclair, Вы писали:
SV.>>Если вы в самом деле это понимаете, как у вас рука поворачивается написать: "Для этого нет необходимости в ООП"? Да, для этого нет необходимости в ООП. ЕЕ ВООБЩЕ НИКОГДА НЕТ. БЕЗ ООП ВСЕГДА МОЖНО ОБОЙТИСЬ. ОНО ОБХОДИМО. S>Хорошо. Напишем тогда так: преимущества у ООП — нету.
SV.>>Покажите, где и как будут реализованы хранение и вычисление, чтобы мы могли сравнить стоимость отладки. Нет, не кода, который хранит и вычисляет, а кода, который будет написан для расчета линейных уравнений на его основе. И не надо писать "в операциях, заданных над этим ADT". Это не значит НИЧЕГО. Конкретизируйте. Я, если угодно, сделаю то же для ООП. Не сделал только потому, что верю, что все и так представляют, как это будет выглядеть. S>А код для расчёта линейных уравнений так и будет написан, как учили в унивеситете. S>Ну, вот для квадратных уравнений мы будем иметь S>
class HighPrecisionNumber
{
public HighPrecisionNumber(decimal source) { ... }
public HighPrecisionNumber(string source) { ... }
public HighPrecisionNumber(byte[] bin) { ... }
...
public static operator +(HighPrecisionNumber n1, n2) { ... }
...
public string ToString() { ... }
public byte[] ToArray() { ... }
...
public Precision { get { ... }; set { ... };
...
private T data;
}
Вот когда такой классец у вас написан, его как черный ящик можно дергать хоть откуда, особо ни о чем не заботясь.
void ResolveSqEq(HighPrecisionNumber a, HighPrecisionNumber b, HighPrecisionNumber c,
ref HighPrecisionNumber x1, ref HighPrecisionNumber x2)
{
var D = b * b - new HighPrecisionNumber(4) * a * c;
var minusB = new HighPrecisionNumber(-1) * b;
var a2 = new HighPrecisionNumber(2) * a;
x1 = (minusB - D.Sqrt()) / a2;
x2 = (minusB + D.Sqrt()) / a2;
}
var a = 10500L;
var b = "8.4534523450230523053258239859328534534583475834758734857348758934758349753489" +
"578349758349752763423546325463546523465236453624562354623465236546523645623546235463563" +
"286583653786537568327856378256237238598978182371283e150";
var c = (byte[]) GetIeee666(d);
var aHpn = new HighPrecisionNumber(a);
var bHpn = new HighPrecisionNumber(b);
var cHpn = new HighPrecisionNumber(c);
a.hPn.Precision = 100;
b.hPn.Precision = 100;
c.hPn.Precision = 100;
HighPrecisionNumber x1, x2;
ResolveSqEq(aT, bT, cT, ref x1, ref x2);
var s = string.Format("Наша группа за отчетный период успешно сосчитала " +
"вакуумный коэффициент коня (это оказался первый корень конно-квадратного уравнения) " +
"с небывалой точностью (100 знаков). Он равен: {0)", x1.ToString());
db3000.SaveIeee666(x2.ToArray());
Если мы не заворачиваем конвертации, хранение и расчеты в класс, то где мы их имеем? Во что превратится код без него? Напишите и выложим оба API на голосование. Вот и будет "точная наука".
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, Sinclair, Вы писали:
SV.>Нет, надо было мне написать код, все же.
SV.>
SV.>class HighPrecisionNumber
SV.>
SV.>Вот когда такой классец у вас написан, его как черный ящик можно дергать хоть откуда, особо ни о чем не заботясь.
А теперь представьте что потребовалось решить уравнение с комплексными коэффициентами.
SV.>
SV.>Если мы не заворачиваем конвертации, хранение и расчеты в класс, то где мы их имеем? Во что превратится код без него? Напишите и выложим оба API на голосование. Вот и будет "точная наука".
Точная наука голосованием? До сих пор бы катались в тарелке на спине у слонов.
Здравствуйте, samius, Вы писали:
S>Я бы объяснил это проще, тем что ООП натягивали на процедурные языки во времена когда было популярно экономить на вызовах, куда уж говорить о создании объекта на каждый вызов.
Гипотеза интересная, но смолток из коробки был построен на сверхпозднем связывании. Экономить они научились уже потом — хотспоттинг и спекулятивные оптимизации были придуманы ровно для него, и уже потом перетащены в джаву. S>Отчасти поэтому мы и имеем кучу работы с сингатурами, сложными правилами совместимости и прочим, вплоть до несовместимости Func/Action в C#. В ФП с более накладным применением аргументов все как-то намного проще.
Я вижу пока что бурление языков; каждый автор имеет своё представление о том, что и кому нужно. Академики откатывают концепции, практики — прикручивают изолентой то, что может пригодиться. В итоге из паскаля мы имеем академический Оберон (явный научный успех и не менее явный провал в популярности) и практичный Delphi — с кучей посторонних вещей, включая (о, ужас!) динамическую типизацию, но категорически популярный.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, SV., Вы писали: SV.>Ну как же. Как он смел заниматься бухгалтерией без плана счетов, утвержденных Минфином РФ с его идентификаторами? Ладно, это была шутка. Не обращайте внимания.
Непонятная шутка. Минфин — ни при чём. Даже если это ваша личная бухгалтерия, с именами счетов "левый карман" и "правый карман", ничего не меняется.
SV.>Я имел в виду запись в отдельной таблице с указанием текущего справочника и вхождения в него.
Я вас по-прежнему не понимаю. Вы мыслите в терминах какого-то конкретного решения, а не в терминах задачи. При чём тут справочник? Справочник можно построить на ходу, просто сделав select distinct sourceAccount from transactions.
SV.>Один простой вопрос. Как вы в этой системе будете вести лицевые счета? Они не видны в отчете, но видны операционисту.
Точно так же. Математика никак не меняется. SV.>А я и не говорю про ООП. Я переключился на уникальные искусственные идентификаторы счета, которые (не) нужны.
Отлично. Я по прежнему не понимаю, для чего вам суррогатные ключи.
SV.>Вот опять мы говорим не про ООП. И опять я скажу, что тут шайбочкой не обойтись.
Беллетристика поскипана. Не имеет отношения к делу.
SV.>Что эти немного абстрактные рассуждения значат применительно к ООП и счетам? Я делаю утверждение, основанное на наблюдениях, а не на какой-то там мифической науке: никто не любит писать объектные модели, но все очень любят ими пользоваться, поскольку они снижают порог вхождения.
О, вот теперь мы подошли к сути. Наконец-то вы делаете хоть какое-то утверждение, которое можно обсуждать.
SV.>Я делаю второе утверждение — нет, и не может быть никакой науки, чтобы доказать или опровергнуть первое утверждение. То есть мы резко перешли к религии. Порог, по-вашему, существует, но измерить его невозможно.
Простите, но на этом нам придётся дискуссию свернуть. Потому что иначе мне придётся в ответ заявить, что анемичные модели имеют по сравнению с объектными моделями значительно более высокую аладибобберность, которая крайне важна, но измерить её научным методом невозможно.
SV.>Нет, нет и еще раз нет. Реальная бухгалтерия обслуживает реальный бизнес.
Вы сейчас смешиваете бухгалтерский учёт и финансовый учёт. Это во-первых.
Во-вторых, финансовый учёт точно так же не работает ни с какими "обьектами", у которых бы было состояние и поведение.
SV.>Без эмоций, вполне спокойно, я заявляю:
Мнение по поводу нужности бухучёта отправлено в дев/нулл как нерелевантное к теме топика. SV.>Опять же, причем тут Лука Пачоли. А чем они все эти века занимались, пока Госплан не выкатил план счетов, интересно?
Неужели отправляли сообщения объектам?
А, нет — записывали проводки в гроссбухи, и готовили отчёты.
SV.>У счета нет состояния. Он его эмулирует. Я, вроде, не скупился в словах, когда это описывал.
Отлично. То есть на самом деле объекта нет, есть некая эмуляция. "Состояние" объекта меняется не в результате взаимодействия с ним других объектов, а в результате действий, произошедших в какой-то посторонней части системы. Ок.
SV.>Это я сначала предложил CalcCurrentBalance(). А уже потом развил свою мысль до CalcBalance(Date forDate = Date.Now). Дорогу, тыскызыть, осиливает идущий. Но я не настаиваю, пусть будет CalcCurrentBalance() и CalcBalance(Date forDate). Это все равно несравненно лучше суммирования проводок везде, где нужен баланс. Непонятно. Вы предлагаете суммировать проводки везде, где нужен баланс. Но при этом это почему-то лучше, чем суммировать проводки везде, где нужен баланс. По-моему, вы спорите с голосами в голове.
SV.>Откуда у Васи acc — как откуда? От AccountingService'а. Как он достукивается до сериса — это платформозависимые вещи. Если Вася пишет плагин (допустим, вебпарт), то и ссылку получает на входе. Если пишет standalone-страницу, просто обращается к сервису и получает у него интерфейс. Затем — что-то типа:
SV.>
О, отлично. То есть вы предлагаете Васе писать код вот так:
var acc = theService.GetAccountByReportIdentifier('78.01');
var balance = acc.CalcBalance();
Да?
И полагаете, что ему это понятнее и удобнее, чем делать всё в одну строчку:
var acc = theService.GetBalance('78.01');
?
Простите, такие смелые утверждения нужно как-то обосновывать.
SV.>Вася этот сидит у меня за спиной сейчас. Только зовут его Катя. Все взято с натуры.
SV.>Дальше, а почему Синклер тупеет? Цель была показать, что имплементация полна сюрпризов, а вы от них ограждены. Можете подставить СВ. Я люблю, когда ОМ скрывает от меня реализацию на первых порах и тупым себя по этой причине не считаю.
Если и считаю, то не по этой. Главное, чтобы она (ОМ) по мере "врубания" и роста хотелок не становилась гирей на ногах, как это случилось с ShP OM. Рич-модель практически всегда становится рано или поздно гирей на ногах. Увы.
SV.>А вот ЭТО и будет нарушением SRP, о котором столько говорилось.
С чего бы это вдруг? Обоснуйте своё утверждение.
SV.>По сути, будет одна большая общая куча функций. Что-то типа WinAPI. Словами не передать, как я ненавижу изучать такие API.
С чего это вы взяли? Вы почему-то думаете, что если вы эту кучу функций засунете в класс Account и заставите порождать его экземпляры на каждый чих, то всё станет понятнее. Я не вижу никаких к этому причин.
Вот как я себе представляю "объектную" модель:
var acc1 = accountingService.GetAccount('78.01');
var acc2 = accountingService.GetAccount('62.03');
var transaction = accountingService.NewTransaction(acc1, acc2, amount);
accountingService.Commit();
Видим четыре объекта, четыре метода.
Вот как бы выглядела анемичная модель:
var result = accountingService.NewTransaction('78.01', '62.03', amount)
Один объект, один метод.
S>>Сколько разных реализаций вы себе представляете у класса Account?
SV.>Я привел пример с двумя реализациями: "реального" счета, то есть, счета, который пасется на базе, и агрегирующего счета, который агрегирует "реальные" счета по заданному признаку. К сожалению, они не являются взаимозаменяемыми. Я не могу сделать перевод с агрегирующего счёта, не указав, какой "реальный" счёт мне нужен. То есть весь полиморфизм у вас — внутри CalcBalance, а точнее — внутри того метода, который выбирает проводки для суммирования. Ну так и выполняйте декомпозицию по этой границе.
Но это, подчеркиваю, не обязательно. Даже если у вас одна реализация, не надо свинячить и пихать в AccountingService everything and kitchen sink.
А что вы называете Everything? Простите, но API AccountingService будет практически 1:1 совпадать c API класса Account.
SV.>Про классиков я не знаю. Можете показать, что надо прочитать и соотнести — я прочитаю и соотнесу.
SV.>Запихать вообще всё в функцию main — НЕнормально, как раз потому, что ответственность нельзя описать словами "сделать всё". Сделать что? Декомпозируйте.
SV.>В реальности, вы же знаете, люди пишут код без комментов и переменные называют однобуквенными именами, чтоб с работы не выгнали. В подавляющем большинстве мест, я подозреваю. Какой тут ООП. Но если вы, допустим, архитектор и совладелец?
То я буду вводить только те объекты, которые обладают поведением. У AccountingService поведение есть.
У Account — нету. Account — это всего лишь строчка '78.01'. Вся политика по поводу того, куда и что можно переводить, а куда нельзя, реализована снаружи Account. Это сегодня нельзя, а завтра — можно. И вообще можно всегда, вопрос только в том, будет ли результирующая отчётность устраивать ограничениям или нет.
SV.>Про сотни и тысячи я не понял. Да хоть миллионы. ООП же не роняет производительность сама по себе.
Вернитесь к тому месту в разговоре, где вы рассказывали про вашу борьбу с прямыми запросами к базе в ShP. Зачем вы это делали, если производительности чистого ООП самого по себе хватало?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, SV., Вы писали:
SV.>Вот когда такой классец у вас написан, его как черный ящик можно дергать хоть откуда, особо ни о чем не заботясь.
SV.>
SV.>void ResolveSqEq(HighPrecisionNumber a, HighPrecisionNumber b, HighPrecisionNumber c,
SV.> ref HighPrecisionNumber x1, ref HighPrecisionNumber x2)
SV.>{
SV.> var D = b * b - new HighPrecisionNumber(4) * a * c;
SV.> var minusB = new HighPrecisionNumber(-1) * b;
SV.> var a2 = new HighPrecisionNumber(2) * a;
SV.> x1 = (minusB - D.Sqrt()) / a2;
SV.> x2 = (minusB + D.Sqrt()) / a2;
SV.>}
SV.>var a = 10500L;
SV.>var b = "8.4534523450230523053258239859328534534583475834758734857348758934758349753489" +
SV.> "578349758349752763423546325463546523465236453624562354623465236546523645623546235463563" +
SV.> "286583653786537568327856378256237238598978182371283e150";
SV.>var c = (byte[]) GetIeee666(d);
SV.>var aHpn = new HighPrecisionNumber(a);
SV.>var bHpn = new HighPrecisionNumber(b);
SV.>var cHpn = new HighPrecisionNumber(c);
SV.>a.hPn.Precision = 100;
SV.>b.hPn.Precision = 100;
SV.>c.hPn.Precision = 100;
SV.>HighPrecisionNumber x1, x2;
SV.>ResolveSqEq(aT, bT, cT, ref x1, ref x2);
SV.>var s = string.Format("Наша группа за отчетный период успешно сосчитала " +
SV.> "вакуумный коэффициент коня (это оказался первый корень конно-квадратного уравнения) " +
SV.> "с небывалой точностью (100 знаков). Он равен: {0)", x1.ToString());
SV.>db3000.SaveIeee666(x2.ToArray());
SV.>
SV.>Если мы не заворачиваем конвертации, хранение и расчеты в класс, то где мы их имеем? Во что превратится код без него? Напишите и выложим оба API на голосование. Вот и будет "точная наука".
Делов-то.
void ResolveSqEq<typename T>(T a, T b, T c,
ref T x1, ref T x2)
{
var D = b * b - new T(4) * a * c;
var minusB = -b;
var a2 = 2 * a;
x1 = (minusB - Sqrt(D)) / a2;
x2 = (minusB + Sqrt(D)) / a2;
}
var a = 10500L;
var b = "8.4534523450230523053258239859328534534583475834758734857348758934758349753489" +
"578349758349752763423546325463546523465236453624562354623465236546523645623546235463563" +
"286583653786537568327856378256237238598978182371283e150";
var c = (byte[]) GetIeee666(d);
var aHpn = HighPrecisionNumber(a, 100);
var bHpn = HighPrecisionNumber(b, 100);
var cHpn = HighPrecisionNumber(c, 100);
HighPrecisionNumber x1, x2;
ResolveSqEq(aT, bT, cT, ref x1, ref x2);
var s = string.Format("Наша группа за отчетный период успешно сосчитала " +
"вакуумный коэффициент коня (это оказался первый корень конно-квадратного уравнения) " +
"с небывалой точностью (100 знаков). Он равен: {0)", HighPrecisionNumberToString(x1));
db3000.SaveIeee666(HighPrecisionNumberToIeee666(x2));
Это не C#, а скорее С++ (на котором я писать не рискнул, т.к. отвык от синтаксиса за годы). У шарпа очень объектно-ориентированный механизм биндинга для инфиксных операций. А в С++ этого нет.
Как видим, нам достаточно иметь набор функций, работающих с нашим high-precision number, как бы он ни был представлен.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Я бы объяснил это проще, тем что ООП натягивали на процедурные языки во времена когда было популярно экономить на вызовах, куда уж говорить о создании объекта на каждый вызов. S>Гипотеза интересная, но смолток из коробки был построен на сверхпозднем связывании. Экономить они научились уже потом — хотспоттинг и спекулятивные оптимизации были придуманы ровно для него, и уже потом перетащены в джаву.
Я собственно про то как ООП из смолтока переползал на C/Pascal и т.п. Там-то походу и потерялась объектность сообщений.
S>>Отчасти поэтому мы и имеем кучу работы с сингатурами, сложными правилами совместимости и прочим, вплоть до несовместимости Func/Action в C#. В ФП с более накладным применением аргументов все как-то намного проще. S>Я вижу пока что бурление языков; каждый автор имеет своё представление о том, что и кому нужно. Академики откатывают концепции, практики — прикручивают изолентой то, что может пригодиться. В итоге из паскаля мы имеем академический Оберон (явный научный успех и не менее явный провал в популярности) и практичный Delphi — с кучей посторонних вещей, включая (о, ужас!) динамическую типизацию, но категорически популярный.
Конечно, когда приходится выбирать между удобством работы с функциями и удобством создания приложений под винду, то альтернативы Delphi фактически не было.
Здравствуйте, Ikemefula, Вы писали:
I>Если бы ты читал внимательно, то заметил бы, что эта разница целиком и полностью из за очереди
Это личные твои домыслы, из-за чего получилась такая разница. Я ХЗ что и как ты смотрел.
I>при том что издержки на GC ничтожны.
Т.е., после того, как уже раз 10 я тебя поправил, ты опять говоришь об издержках на выделение памяти в GC?
А что мы сейчас вообще обсуждаем, не пояснишь?
I>Эта разница как раз и натолкнула меня на мысль о том, что твои данные отличаются от реальных минимум на порядок-другой.
Меня твоя разница пока натолкнула на две мысли:
1. Не понял, что надо в тестах замерять.
2. Не знаешь куда смотреть в результатах теста.
V>>Дык, это ведь ты код требуешь. Я-то эту тему давно прошел и все выводы давно сделал. Мне лишь для своей эрудиции интересно понагибать последний дотнет. V>>В плане числодробления уже нагибал — сосет не нагибаясь как и прежде. В плане GC они там что-то сильно много хвалились — надо проверить насколько соответсвует действительности.
I>Ничего, если я тебе твои слова покажу ? I>
I>Время надо. Для адекватного воспроизведения покодогенерить неплохо бы, а то непонятно что смотреть будем...
I>Попробую этой время найти ближе к выходным. Самому интересно, что покажет мой сегодняшний рабочий комп и новый дотнет.
Именно, а ты как хотел? Любые тесты вокруг ненулевого поколения в GC заведомо нетривиальны.
I>
I>И зря ты свой тест не даешь, коль он у тебя уже есть. Несерьезный ты человек.
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, 0x7be, Вы писали:
SV.>>>Просто потому, что мы мыслим объектами. 0>>А это точно правда?
SV.>Это называется "понятийное мышление". В норме человек к 5 годам им овладевает в степени, достаточной для повседневного применения.
Ну... императивным мышлением даже животные обладают: "чтобы хозяин меня покормил надо подойти к нему и помяукать". Или, "чтобы поймать мышку надо (1), (2), (3) ..."
А в случае объектов вопрос спорный, лично мне императивное мышление намного ближе и нативнее.
Здравствуйте, Ikemefula, Вы писали:
I>>>"прирост до 50 раз " @ vdimas V>>Этот множитель сложился из двух множимых. См. исходный пост на русском языке: http://www.rsdn.ru/forum/philosophy/4843592.1.aspx
. I>То есть, ты разницу между IList и List помножил на разницу между ручной и встроеной серилизацией ?
Наоборот, разделил общий эффект на разницу м/у ручной и встроенной сериализацией, чтобы получить прирост от тупой замены абстрактных типов на конкретные.
I>Но по любому , ты снова ошибся хотя уже не на порядок
Нет.
I>Итого, максимальная разница между List и IList в 2.5 раза. С valuetype вместо object разница еще меньше, всего 1.5 раза. I>Вероятно "от 3-х до ~10-ти" ты получил вообще на пустых итерациях
Итого, у тебя опять работает заведомо синтетика и заведомо некорректная. Даю тебе вторую попытку. Вместо 10КК прогонов по циклу попробуй прогон по десяткам элементов (это ближе к реальной задаче сериализации разветвленного графа объекта в памяти), а внешний цикл пусть будет 10КК/x, где x — кол-во элементов.
Сразу получишь более 3-х раз разницы (у меня — 3.75). Ну а потом погоняй стоимость вызова других методов, например стоимость обращения к элементу по индексу (иначе нахрена именно IList??).
В общем, более 8-ми раз на реальных задачах выходила разница из-за простой замены IList<> на конкретные типы. По приведенной ссылке — результаты с реального проекта.
Думаю, более корректным будет тест с глубиной вложенности объектов хотя бы 2. Т.е. было бы неплохо сделать коллекцию в коллекции, разбив эти 100 элементов хотя бы 10*10.
V>>А теперь тебе надо бъяснить пассаж насчет Enumerable.ElementAt. I>Объясняю — использование List может быть очень дорогим удовольствием, а хочется, что бы некоторые функции вроде Linq2Objects работали крайне быстро, выход — IList<>
Это не объяснение, а туманность Андромеды. Покажи, где IList<> будет быстрее List<>.
I>>>Успокойся, не волнуйся, твои сценарии самые-самые, и да, это не беда, что только у тебя они используются. I>>>Для моих сценариев IList<> в самый раз, просто потому что List<> это ОЧЕНЬ дорогой контейнер. Настолько дорогой, что использовать его нельзя во многих сценариях.
V>>Дык, никто не мешает использовать любые конкретные типы, в т.ч. обычный массив. И таки, если речь об итерировании, то итерирование по List<> нифига не дорогое удовольствие, в отличие от IList<>. I>Ты похоже не понимаешь — если List это очень дорого, то и массив тоже будет так же дорого.
Да, пока что не понимаю, пока ты не показал, где IList<> будет быстрее List<>.
I>Реальная разница в 2.5 раза на почти пустой итерации. Если цикл чуть сложнее суммы элементов, эта разница становится ничтожной.
Для задач просто чтения элементов, о которой речь в сериализации, разница оказалась катастрофической. При десериализации тоже тоже оказалась в несколько раз, бо при десериализации используются те самые остальные методы интерфейса List/IList для наполнения коллекций.
Здравствуйте, vdimas, Вы писали:
I>>Если бы ты читал внимательно, то заметил бы, что эта разница целиком и полностью из за очереди
V>Это личные твои домыслы, из-за чего получилась такая разница. Я ХЗ что и как ты смотрел.
Не мои, а твои Я то код вижу, а ты — нет.
I>>при том что издержки на GC ничтожны.
V>Т.е., после того, как уже раз 10 я тебя поправил, ты опять говоришь об издержках на выделение памяти в GC? V>А что мы сейчас вообще обсуждаем, не пояснишь?
Я говорю о времени которое тратит GC относительно издержек на очереди согласно твоей же модели. На тех цифрах что ты выдал издержками на GC можно пренебречь.
I>>Эта разница как раз и натолкнула меня на мысль о том, что твои данные отличаются от реальных минимум на порядок-другой.
V>Меня твоя разница пока натолкнула на две мысли: V>1. Не понял, что надо в тестах замерять. V>2. Не знаешь куда смотреть в результатах теста.
Ты выдал нечто вроде: "GC падает навзничь"
Сообщаю — на твоих цифрах все в шоколаде — издержки на GC ничтожны.
I>>Ничего, если я тебе твои слова покажу ? I>>
I>>Время надо. Для адекватного воспроизведения покодогенерить неплохо бы, а то непонятно что смотреть будем...
I>>Попробую этой время найти ближе к выходным. Самому интересно, что покажет мой сегодняшний рабочий комп и новый дотнет.
V>Именно, а ты как хотел? Любые тесты вокруг ненулевого поколения в GC заведомо нетривиальны.
Здравствуйте, vdimas, Вы писали:
I>>>>"прирост до 50 раз " @ vdimas V>>>Этот множитель сложился из двух множимых. См. исходный пост на русском языке: http://www.rsdn.ru/forum/philosophy/4843592.1.aspx
. I>>То есть, ты разницу между IList и List помножил на разницу между ручной и встроеной серилизацией ?
V>Наоборот, разделил общий эффект на разницу м/у ручной и встроенной сериализацией, чтобы получить прирост от тупой замены абстрактных типов на конкретные.
То есть во фразе "множитель сложился из двух множимых" слово "сложился" надо понимать как произведение, но при этом надо делить ?
I>>Итого, максимальная разница между List и IList в 2.5 раза. С valuetype вместо object разница еще меньше, всего 1.5 раза. I>>Вероятно "от 3-х до ~10-ти" ты получил вообще на пустых итерациях
V>Итого, у тебя опять работает заведомо синтетика и заведомо некорректная. V>Даю тебе вторую попытку. Вместо 10КК прогонов по циклу попробуй прогон по десяткам элементов (это ближе к реальной задаче сериализации разветвленного графа объекта в памяти), а внешний цикл пусть будет 10КК/x, где x — кол-во элементов. V>Сразу получишь более 3-х раз разницы (у меня — 3.75).
Никакого "сразу" быть не может. Время колеблется от прогона к прогону, что для дотнета вобщем то норма.
Вот результаты 10 прогонов двух тестов — total(for IList<>)/total(for List<>)
4.0 3.5 2.0 2.5 2.7 2.9 2.3 2.4 2.9 2.3
Дальше мне стало лень
>Ну а потом погоняй стоимость вызова других методов, например стоимость обращения к элементу по индексу (иначе нахрена именно IList??).
Стоимость обращения к элементу по индексу в принципе не может зависеть от длины списка что собственно и показывают результаты.
V>В общем, более 8-ми раз на реальных задачах выходила разница из-за простой замены IList<> на конкретные типы. По приведенной ссылке — результаты с реального проекта.
После твоих "уточнений" я всерьез думаю ты или попутал результаты(массив вместо List и тд) или просто сочиняешь, выбирай сам.
V>Думаю, более корректным будет тест с глубиной вложенности объектов хотя бы 2. Т.е. было бы неплохо сделать коллекцию в коллекции, разбив эти 100 элементов хотя бы 10*10.
Это ни о чем. Эффект появится только в двумерном выравненом массиве и никак не в списке.
I>>Объясняю — использование List может быть очень дорогим удовольствием, а хочется, что бы некоторые функции вроде Linq2Objects работали крайне быстро, выход — IList<>
V>Это не объяснение, а туманность Андромеды. Покажи, где IList<> будет быстрее List<>.
Это очень просто, IList<> может иметь любую реализацию, т.е. оптимизация под конкретные сценарии, не любые а именно те что нужны. У меня вот нет ручной серилизации
Смотри внимательно, моя реализация IList
Contains O(N/K)
IndexOf O(N/K + K/4)
Remove — O(N/K)
RemoveAt — O(N/K + K/4)
RemoveAt(0) — O(1) для сравнения List имеет здесь O(N), что в линейном алгоритме даёт O(N^^2) — очень жОсткое ограничение, т.е. просто так использовать практически никак
Дополнительно моя реализация никогда не попадёт в LOH, например это проявляется в том, что в GC вызывается примерно на порядок реже и прога не валится от OOM после получаса зависания в GC.
В сумме это примерно так — операции которые педалили по 6 часов и более теперь укладываются в 5 минут, а время отклика UI уменьшилось в среднем в 10 раз.
V>>>Дык, никто не мешает использовать любые конкретные типы, в т.ч. обычный массив. И таки, если речь об итерировании, то итерирование по List<> нифига не дорогое удовольствие, в отличие от IList<>. I>>Ты похоже не понимаешь — если List это очень дорого, то и массив тоже будет так же дорого.
V>Да, пока что не понимаю, пока ты не показал, где IList<> будет быстрее List<>.
Вероятно ты IList<> понимаешь исключительно как ((IList<>)List<>)
I>>Реальная разница в 2.5 раза на почти пустой итерации. Если цикл чуть сложнее суммы элементов, эта разница становится ничтожной.
V>Для задач просто чтения элементов, о которой речь в сериализации, разница оказалась катастрофической. При десериализации тоже тоже оказалась в несколько раз, бо при десериализации используются те самые остальные методы интерфейса List/IList для наполнения коллекций.
Чушь, разница в добавлении от силы в 10% в вырожденых случаях.
Инлайн дает эффект только тогда, если тело метода тривиальное. Добавление "тяжелая" операция — раскрой метод тулом и посмотри, ты сэкономишь ровно один виртуальный вызов, что для Add вообще ничего. Скажем Array.Resize в сумме съест намного больше.
Здравствуйте, Sinclair, Вы писали:
S>>Я бы объяснил это проще, тем что ООП натягивали на процедурные языки во времена когда было популярно экономить на вызовах, куда уж говорить о создании объекта на каждый вызов. S>Гипотеза интересная, но смолток из коробки был построен на сверхпозднем связывании. Экономить они научились уже потом — хотспоттинг и спекулятивные оптимизации были придуманы ровно для него, и уже потом перетащены в джаву.
Ну а причем тут смолток? Он более-менее оформился лет через 10 после "мейнстримной" разновидности ООП. Этот язык — Симула 67 — отличается от современных ООЯ только в деталях. К примеру, в нем небыло множественного наследования (ни в каком виде — ни в виде трейтсов, ни в виде интерфейсов), а конструктор был один на класс и тело конструктора и объявления класса были одним блоком (те, кто видел ООП в F#, например, должен понять о чем я говорю), неймспейсы реализовывались с помощью анонимных классов. Самые обычные ссылки, самые обычные классы с "наследованием", обычные методы, виртуальные методы. Никакого "есть только объекты, обменивающиеся сообщениями, которые сами объекты" (ну, были еще и легкие потоки, активные объекты и "дискретные симуляции" но от этого произошли другие ветки ООП и совсем не ООП).
Гипотеза samius отлично подтверждается фактами:
Первый ООЯ был диалектом процедурного языка Алгол 60. Первоначально создатели даже собирались ограничиться препроцессором Алгола, но потом им понадобились расширения Алгола 60 вроде ссылок.
Поэтому нет в мейнстрим-ооп никакой "объектной арифметики" и "блоков кода", которым посылается сообщение "выполняйся". ООП появилась как расширение обычного процедурного языка, который на первый взгляд от паскаля отличается только тем, что у него типы не постфиксно после двоеточия указываются, а префиксно — как в C. (Точнее, конечно, это паскаль от него почти не отличается и типы в C как в нем указываются)
Концепции ООП появлялись таким способом: вот интересный (и дешевый в реализации) эффект — как мы можем его использовать?
Началось все с того, что понадобилось придумать новый (быстрый) способ передачи параметров в процедуры. Стандартные алголовские способы: по значению и по имени были медленными по разным причинам. Тогда Хоар изобрел ссылки и null. Раз уж структурная эквивалентность оказалось сложной в реализации, сравнивать стали адреса, по которым "объекты" располагаются — появилось identity.
Обратили внимание на то, что блок памяти B, структурированный в начале так же, как и блок A можно обрабатывать процедурами, написанными для работы с A — появился "префиксинг" (даже синтаксически объявление класса родителя было префиксным), под который потом подвели идеологию и назвали "наследованием" (ну и понятно, почему сначала никаких "множественных наследований" не было — что такое "множественный префиксинг"?).
К рекордам добавили процедуры, диспетчеризующиеся по одному аргументу. Почему именно по одному? Потому что по n > 1 — сложно в реализации. и т.д.
Кей же и прочие смолтокеры захотели сделать не такой вот "натянутый" на структурное программирование ООП, а идеологически чистый и непротиворечивый. Для этого они подвели базу под все эти технические срезания углов. Получилась чистая реализация идей, придуманных для быстроты и простоты реализации, только медленная и сложная. Они не смогли все это заставить вертеться с приемлимой скоростью до 90-х годов, когда стало уже поздно. Чтоб ввести Симула-лайк ООП в мейнстрим понадобилось только (временно) отказаться от сборщика мусора.
Однако, вся философия и методология ООП, паттерны и юнит-тесты и т.д., придуманные смолтокерами не пропали, а были адаптированы мейнстримом.
Смолток — это не "изначальное древнее ООП", а возрождение умирающего старого и реформация неправильного ООП, загнувшееся, правда, раньше нем неправильное, пока по настоящему древнее ООП все продолжало умирать. Ну и, понятно, философия ООП, которая превратила все картины, загораживающие дырки на обоях, в "краеугольные камни" концепции и "имманентные особенности человеческого мЫшленья".
S>академический Оберон (явный научный успех и не менее явный провал в популярности)
Ничего академического в нем нет. Это — очевидно неудачная — попытка слепить как раз "практический" язык из академических наработок Algol, Simula, Mesa, Cedar, в очень незначительной степени — Smalltalk. Научная ценность и техническая новизна Оберона равна нулю. "Академическим" он тут называется практиками исключительно потому, что для "практика" "академический" — это ругательство, а общеупотребимые ругательства правилами запрещены.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Здравствуйте, samius, Вы писали:
SV.>>Вот когда такой классец у вас написан, его как черный ящик можно дергать хоть откуда, особо ни о чем не заботясь. S>А теперь представьте что потребовалось решить уравнение с комплексными коэффициентами.
Тогда вы наУчите свои числовые обертки не только точности, но и мнимости. Как это конкретно сделать — в смысле, с наследованием реализаций или нет, а если с наследованием, то чего от чего — я с ходу не соображу, поскольку соответствующую математику со второго курса не использовал. Если кто-то поможет, то заранее ему спасибо.
SV.>>Если мы не заворачиваем конвертации, хранение и расчеты в класс, то где мы их имеем? Во что превратится код без него? Напишите и выложим оба API на голосование. Вот и будет "точная наука". S>Точная наука голосованием? До сих пор бы катались в тарелке на спине у слонов.
Вы видите, что "точная наука" взята в кавычки? Это саркастическая ссылка на "точную науку дизайна", в которую я не верю ни на грамм, из параллельной дискуссии в соседней подветке.
S>void ResolveSqEq<typename T>(T a, T b, T c,
S> ref T x1, ref T x2)
S>{
S> var D = b * b - new T(4) * a * c;
S> var minusB = -b;
S> var a2 = 2 * a;
S> x1 = (minusB - Sqrt(D)) / a2;
S> x2 = (minusB + Sqrt(D)) / a2;
S>}
Перевод ResolveSqEq в обобщенный вид я (с опозданием) поддерживаю. Это очень правильно. Надеюсь, MTD досюда не дочитает
S>var a = 10500L;
S>var b = "8.4534523450230523053258239859328534534583475834758734857348758934758349753489" +
S> "578349758349752763423546325463546523465236453624562354623465236546523645623546235463563" +
S> "286583653786537568327856378256237238598978182371283e150";
S>var c = (byte[]) GetIeee666(d);
S>var aHpn = HighPrecisionNumber(a, 100);
S>var bHpn = HighPrecisionNumber(b, 100);
S>var cHpn = HighPrecisionNumber(c, 100);
S>HighPrecisionNumber x1, x2;
S>ResolveSqEq(aT, bT, cT, ref x1, ref x2);
S>var s = string.Format("Наша группа за отчетный период успешно сосчитала " +
S> "вакуумный коэффициент коня (это оказался первый корень конно-квадратного уравнения) " +
S> "с небывалой точностью (100 знаков). Он равен: {0)", HighPrecisionNumberToString(x1));
S>db3000.SaveIeee666(HighPrecisionNumberToIeee666(x2));
S>
S>Это не C#, а скорее С++ (на котором я писать не рискнул, т.к. отвык от синтаксиса за годы). У шарпа очень объектно-ориентированный механизм биндинга для инфиксных операций. А в С++ этого нет. S>Как видим, нам достаточно иметь набор функций, работающих с нашим high-precision number, как бы он ни был представлен.
А тут я снова ничего не понял. В вашем варианте HighPrecisionNumber — это что? Handle?
Здравствуйте, SV., Вы писали:
SV.>Здравствуйте, samius, Вы писали:
S>>А теперь представьте что потребовалось решить уравнение с комплексными коэффициентами.
SV.>Тогда вы наУчите свои числовые обертки не только точности, но и мнимости. Как это конкретно сделать — в смысле, с наследованием реализаций или нет, а если с наследованием, то чего от чего — я с ходу не соображу, поскольку соответствующую математику со второго курса не использовал. Если кто-то поможет, то заранее ему спасибо.
В том и фишка, что хочется работать с разными представлениями одним кодом, а не запихивать в один класс все возможные представления.
По идее, обобщенный метод — это скорее ФП решение. А для ООП нужно городить INumber и учить его складываться, умножаться и т.п. с самим собой. Либо вводить INumberArithmetic, который будет оперировать INumber-ами.
SV.>>>Если мы не заворачиваем конвертации, хранение и расчеты в класс, то где мы их имеем? Во что превратится код без него? Напишите и выложим оба API на голосование. Вот и будет "точная наука". S>>Точная наука голосованием? До сих пор бы катались в тарелке на спине у слонов.
SV.>Вы видите, что "точная наука" взята в кавычки? Это саркастическая ссылка на "точную науку дизайна", в которую я не верю ни на грамм, из параллельной дискуссии в соседней подветке.
А в проблемы неудачного дизайна верите?
Здравствуйте, samius, Вы писали:
S>По идее, обобщенный метод — это скорее ФП решение. А для ООП нужно городить INumber и учить его складываться, умножаться и т.п. с самим собой. Либо вводить INumberArithmetic, который будет оперировать INumber-ами.
Для ООП нужен объект Вычислитель, который может работать с числами самой разной природы.
Здравствуйте, SV., Вы писали:
SV.>А тут я снова ничего не понял. В вашем варианте HighPrecisionNumber — это что? Handle?
А как раз это — неважно.
Пусть это будет, скажем, ASCIIZ-строка, в которой хранится нужное нам количество цифр.
Или структ из тридцати интов для хранения мантиссы и ещё одного — для экспоненты.
Прикладному коду это совершенно безразлично.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>По идее, обобщенный метод — это скорее ФП решение. А для ООП нужно городить INumber и учить его складываться, умножаться и т.п. с самим собой. Либо вводить INumberArithmetic, который будет оперировать INumber-ами.
I>Для ООП нужен объект Вычислитель, который может работать с числами самой разной природы.
Для самой разной природы чисел не нужен. Нужен лишь для той природы, в рамках которой выполняется решение. Для вычислений другой природы подсовывай другой вычислитель.
Здравствуйте, samius, Вы писали:
S>>>А теперь представьте что потребовалось решить уравнение с комплексными коэффициентами.
SV.>>Тогда вы наУчите свои числовые обертки не только точности, но и мнимости. Как это конкретно сделать — в смысле, с наследованием реализаций или нет, а если с наследованием, то чего от чего — я с ходу не соображу, поскольку соответствующую математику со второго курса не использовал. Если кто-то поможет, то заранее ему спасибо. S>В том и фишка, что хочется работать с разными представлениями одним кодом, а не запихивать в один класс все возможные представления. S>По идее, обобщенный метод — это скорее ФП решение. А для ООП нужно городить INumber и учить его складываться, умножаться и т.п. с самим собой. Либо вводить INumberArithmetic, который будет оперировать INumber-ами.
Смотрите. Функция-решатель у меня изначально была отдельной функцией, не входящей ни в какой класс. Просто в силу ее функциональной природы. Про комплексные числа я не подумал, но зато (наверное) подумал Sinclair, и сделал функцию обобщенной. Шучу. Достаточно захотеть иметь обобщенное решение для простых чисел и чисел с повышенной точностью. Ну, еще при имплементации иметь в виду, что унарные операции могут для типа не поддерживаться (я имел). Так вот, с необходимостью обобщить функцию я согласился. Это отвечает на вашу претензию?
Что интересно, для меня обобщение ничего не меняет. Мой класс — способ упаковать различные конвертации и хранение, не дать им расползтись по всему проекту.
SV.>>Вы видите, что "точная наука" взята в кавычки? Это саркастическая ссылка на "точную науку дизайна", в которую я не верю ни на грамм, из параллельной дискуссии в соседней подветке. S>А в проблемы неудачного дизайна верите?
Если рассматривать проблемы у каких-то конкретных людей — почему нет?