Здравствуйте, igna, Вы писали:
I>В статьях про "Immutable object" или про "Неизменяемый объект" в Википедии, во всех примерах речь идет о типах, все экземпляры которых неизменяемы, хотя согласно определениям данным в начале статей i в примере ниже является неизменяемым объектом:
I>
I>int const i = 123;
I>
I>Так ли это, можно ли назвать i здесь immutable?
Я не теоретик и определения из статей не читал, но если речь о С++, то, имхо, да, вполне себе immutable
Здравствуйте, igna, Вы писали:
I>В статьях про "Immutable object" или про "Неизменяемый объект" в Википедии, во всех примерах речь идет о типах, все экземпляры которых неизменяемы, хотя согласно определениям данным в начале статей i в примере ниже является неизменяемым объектом:
I>
I>int const i = 123;
I>
I>Так ли это, можно ли назвать i здесь immutable?
В контексте "Immutable object" — нет. Immutable object здесь 123. А i — это имя переменной (пусть и immutable).
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Уточни, пожалуйста, оно говорит о каких-то конкретных случаях объявления ссылки, или о всех, включая объявление ссылки на локальную переменную?
I>О всех кроме ссылок являющихся "non-static data member".
Да, ты прав. Теперь прав (спустя 25 лет существования ссылок). тыц. тыц, тыц...
Теперь референсы формально считаются переменными, невзирая на то, что память для хранения значения может и не выделиться. И просто потому что так меньше исправлять в стандарте.
Здравствуйте, igna, Вы писали:
I>Ложная. Указатель, хоть в программировании, хоть дорожный никогда не имеет значения того, на что он указывает.
Именно об этом и речь.
I>А что означает имя, само себя или то, что оно именует, зависит от контекста.
Имя никогда не означает "само себя".
L>>Да, именно это там и написано.
I>Ты все-каки задумайся над тем, что ратуя за строгое различение между именем и тем, что оно именует, ты сам употребил имя Луна во втором значении, а не написал чего-либо вроде:
Я не ратую за строгое различение.
I>
I>Палец указывающий на то, имя чего Луна, не есть то, имя чего Луна.
Это не до конца исправленная версия.
Нечто, именуемое "Палец", проиводящее действие, именуемое "указывание", в отношении того, имя чего Луна, не есть то, имя чего Луна.
Здравствуйте, igna, Вы писали:
S>>Идентификатор i никак не является объектом.
I>Вот прям никак. А samius чем является, человеком или его псевдонимом на rsdn.ru?
Здравствуйте, Sinclair, Вы писали:
S>К окончанию программы у нас останется ровно одна версия консоли — та, которая вошла в результат. S>Её мы и будем трактовать как "настоящую"
По моему ты описал то что называется уникальными типами в языке Clean. То есть переменную гарантированно имеющую
всегда только одну ссылку, подробнее:
Здравствуйте, DarkGray, Вы писали:
S>>Есть формальное определение отношение эквивалентности и мне не известно ни одного повода считать что его можно ослабить, в том числе для ООП.
DG>также посоветую прочитать что-то помимо букваря. DG>кроме классической эквивалентности из первого класса школы, есть также, например, эквивалентность для нечетких множеств. DG>соответственно необходимо привести пруфлинк, что в ООП нельзя применять нечеткие множества и соответствующую эквивалентность.
Предлагаю для начала представить пруфлинк что отношение сравнения даблов по эпсилону является отношением нечеткой эквивалентности, в частности что для него выполняется нечеткая транзитивность
DG>зы DG>http://www.dmtsoft.ru/bn/476/as/oneaticleshablon/ DG>читать до просветления что такое нестрогое отношение эквивалентности (оно же нечеткое отношение эквивалентности)
Google: No results found for "нестрогое отношение эквивалентности"
S>Можете продемонстрировать на простом примере? Вот в этой несложной программе, где именно боттлнек (чур, профайлер не запускать):
для точного определения ботлнека не хватает статистики(или экспертных оценок):
как часто используется ?, какое распределение запросов по длине rack, какое распределение слов в словаре по длине,
насколько тормозит файловая система, и как часто файл словаря попадает в memory-кэш ос.
вычислительное узкое место в этом сравнении
return from line in FileLines(dictionary)
where line.Length == originalRack.Length
where racks.Contains(Canonicalize(line))
select line;
сложность: 27 вызовов * кол-во слов в словаре с заданной длиной * (sort слова + (1+26 * кол-во '?') сравнений слов)
И скорее всего именно поэтому его уже пытались оптимизировать (вынесен racks и добавлено сравнение длин).
racks стоит заменить на Set/Dictionary вместо массива
алгоритмический bottleneck в строках:
foreach (char c in "ABCDEFGHIJKLMNOPQRSTUVWXYZ")
Console.WriteLine("{0}+{1} : {2}", rack, c, SearchDictionary(rack + c).Join());
их стоит заменить на
SearchDictionary(rack + "?") с последующей группировкой ответов по добавленной букве
далее стоит сделать сравнение по образцу вместо перемножения
образец разбивается на две части: определенные отсортированные буквы и кол-во ?
на основе строки формируются последовательно отсортированные перестановки с длиной по кол-ву определенных букв в образце
оба этих изменения дадут уменьшение узкого места до:
кол-во слов в словаре с заданной длиной * (sort слова + С(n-1, 1 + кол-во '?') * сравнений букв)
дальше можно заниматься всякими доп. оптимизациями:
вынос построения словаря из под цикла
(при необходимости)замена array.sort на свою сортировку, заточенную под сортировку коротких массивов из небольшого набора символов
(при необходимости)чтение всего(или большими кусками) словаря в stringbuilder и там же его обработка в виде набора символов без создания отдельных экземпляров строк
(при необходимости) замена char-ов на байты
(при необходимости) четырех-символьное сравнение за раз (через представление строк через int)
DG>>и если использовать идеальную модель в которой ничего этого нет, то не получится ни описывать, ни решать проблемы и задачи, которые в действительности происходят в программах и в реальной жизни. S>Чушь. Почитайте же хоть что-нибудь из букварей. Никакая, подчёркиваю, никакая реальная машина не является более мощной, чем машина Тьюринга.
лучше ты прочитай что-нибудь еще кроме букварей. скоро уж внукам необходимо будет читать буквари, а ты всё о них талдычишь.
ты сейчас используешь лишь один показатель — алгоритмическая эквивалетность(мощность).
кроме него еще есть, например, вычислительная сложность(кол-во тактов необходимое для выполнения), информационная сложность (кол-во бит необходимое для описания программы), выразительная мощность и т.д.
алгоритмическая эквивалентность не обещает, что перевод программы при сохранении вычислительной сложности программы из одного тьюринг полного языка в другой тьюринг полный язык является не NP-полной задачей (а значит практически выполнимой).
соответственно, какая разница что они в теории эквиваленты, если на практике этим вспользоваться нельзя.
при этом, например, перевод из C++ в asm с сохранением вычислительной мощности — является P-задачей, а из asm в C++ — уже NP-задачей. соответственно, C++ получается мощнее чем asm с точки зрения выразительности.
тоже самое и с другими задачами: проверка корректности, слиянии двух алгоритмов и т.д.
в разных моделях эти задачи будут решаться с разной вычислительной сложностью.
например, проверка корректности работы с памятью для C#-а является чуть ли не линейной задачей, а проверка C++-программы будет экспонециальной от размера программы (а значит опять же практически не разрешимой).
тоже самое и с разными моделями ООП: алгоритмически они эквиваленты, но обладают разной выразительной мощностью
DG>>я их не путаю. а знаю, что любое отношение идентичности является таковым только в небольшой локальной модельке, как только модель берется чуть шире оно сразу из отношения идентичности переходит в отношение эквивалентности. S>И тем не менее вы пишете бред типа "сравнение состояния объектов вводит ещё одно отношение идентичности".
если что-то непонятно, то лучше спроси. это все-таки формум, а не диссертация по математике, и тут общаются на ЕЯ со всеми его плюсами и недостатками, а не на математической нотации которую ты больше любишь.
DG>>но вот такой, например, не однозначный вопрос: допустим локальное время с точки зрения каждого объекта непрерывное. DG>>но при этом является ли оно таковым же с точки зрения стороннего наблюдателя: как внутри системы? так и снаружи? S>Понятие непрерывности ко времени в дискретной системе неприменимо. Разве это не очевидно? S>Если нет — погуглите определение термина "непрерывность времени".
ты хороший образец оппонента, который руководствует логикой: если не получается ничего сказать по существу — придеритель к выбранным терминам, если не получилось придраться к терминам придеритель к грамотности.
DG>>у меня один критерий — можно ли это применить к реальности или нет. S>Всё можно применить к реальности. Но если хочется лезть в область теории программирования (а это совершенно необязательно), то нужно привыкнуть к тому, что в модели главное — непротиворечивость. А похожесть терминов на бытовые слова играет второстепенную роль.
любое утверждение необходимо обосновывать, а не просто ссылаться на авторитеты. если человек часто выдает какие-то утверждения без обоснований — это показывает, что он не понимает то, о чем он говорит.
> то нужно привыкнуть к тому, что в модели главное — непротиворечивость.
а обосновать это можешь? как ты любишь — формально в математической нотации?
опять же главное для чего? кроме обоснования как я уже несколько раз говорил в треде — очень важно понимать границы применимости какдого утверждения.
зы
вон диалектика, вообще, утверждает — что нет противоречий -> нет движения(развития), а значит нет и жизни.
а ты предлагаешь при моделирование отсутствие противоречий объявить самым главным критерием.
S>Вот, к примеру, не-физики очень обижаются, когда физики говорят им, что переноска тяжестей по горизонтальной поверхности работы не совершает.
и как всегда обе стороны правы. и противоречие наносное из-за использования разных моделей.
при этом переноска человеком тяжести в горизонтальном плоскости с точки зрения одной модели(бытовой) — не является переном тяжести в горизонтальной плоскости в другой модели(физической).
DG>>вот твой вариант может описать ситуацию с гибернейтом, в чем там проблема? и как ее решать? или не может? если не может — значит в топку. S>Конечно же может. А в чём там проблема?
и как задается функция идентичности с точки зрения распределенной системы для объектов которые сейчас спят?
DG>>есть же, конечно. как только ты начинаешь утверждать, что сообщения гарантированно доходят — это вводит требование, что пространство непрерывно. S>Опять каша в голове. Пространство — это категория взаиморасположенности и протяжённости.
если лента тьюринга не пространство (как и любая память в других машинах), то что это?
S>Ни о чём подобном модель ООП не берётся рассуждать. S>Гарантия доставки не имеет никакого отношения к пространству.
неправда. для гарантированности доставки (тем более за разумное время) пространство должно обладать определенными свойствами.
это как-то слабо похоже на "не имеет никакого отношения".
DG>>что опять же не умеет описывать поведение такой реальной штуки, как работу тонкого клиента в браузере в мобильнике. S>Очередной бред. Оставим гон про разрывность пространства, сосредоточимся на осмысленном разговоре о негарантии доставки. S>Очевидно, что модель с гарантией доставки легко может эмулировать модель без гарантии — достаточно ввести посредника, который будет либо доставлять сообщения, либо дропать/отказывать, в зависимости от своего состояния. S>Обратное смоделировать в общем случае невозможно.
передергиваешь, либо не понимаешь.
есть две модели — в одной все сообщения гарантированно доставляются, в другой — есть несколько различных классов доставки: гарантированная, негарантированная и т.д.
первая модель является частью второй, а значит всё смоделированное в первой модели в 1-1 переносится во вторую модель.
а обратное как раз неверно. для корректного же описания алгоритма описанного в терминах второй модели при описании в первой модели может уже потребоваться экспонециальный рост сложности (что на практике непременимо).
DG>>если этого нет, то какая модель это описывает? вот, например, в аналогом компьютере — нет никакой последовательности сообщений. при этом его работу какая модель описывает? и в чем ее отличие от Канонической Модели ООП с большой буквы? S>Его работу описывает какая-то вычислительная математика. ООП будет из рук вон плохо моделировать аналоговый компьютер. А вы этого не знали?
где обоснование?
DG>>например, когда арифметика говорит, что 1 + 1 = 2, она накладывает ограничение, что эти единицы есть независимы друг от друга, являются однородными объектами и т.д. если же мы хотим в реальности сложить 1 программиста с 1 автобусом будут требоваться более сложные модели(теории), чем арифметика. например, теория множеств и категорий S> Почитайте же букварь! S>Арифметика строится на теории множеств, а не наоборот! Арифметика сложнее теории множеств!
что значит сложнее? формализуй.
ты постоянно требуешь что тебе всё разжевали и формализовали, при этом ни одно свое нетривиальное утверждение ты формализовать не можешь... по крайней мере еще ни разу не сделал
DG>>при чем вики говорит про тоже самое: там нет, например, никакого требования идентичности. S>Просто вики, на которую вы ссылаетесь, не является формальной моделью ООП. Там написан текст для среднестатистического читателя.
давай ссылку на формальное определение. или может оно вообще существует только в твоей голове?
DG>>давай разбирать. в итоге, конечно, всё сведется к тому, что на данном примере накручено две ООП-модели. для той, которая считает, что Ping — это полноценное сообщение, Pong не будет ответом, а для той — которая считает, что Ping это есть половинка запроса Ping/Pong — будет ответом. DG>>но разобраться пожалуйста — это всегда интересно. S>Если хочется выбрать асинхронную модель, то набор событий станет несколько другим: S>1. отправить Пинг S>2. получить Пинг S>3. отправить Понг S>4. получить Понг S>Из-за асинхронности наша модель времени стала несколько слабее. Тем не менее, 4е событие не может произойти раньше первого.
ок.
возьмем "отправить Пинг" и исходную программу.
в какой точке программы Client может считать, что "отправить Пинг" с точки зрения гарантированности доставки выполнено?
DG>>это с точки зрения модели, когда каждое вызов функции есть отдельное сообщение. DG>>так же, как я же уже выше говорил, здесь есть и вторая модель, когда только вместе ping/pong образуют одну пару запрос/ответ. S>Я же говорю: в модели главное — непротиворечивость. Если в вашей модели ответ приходит раньше запроса, то вы где-то ошиблись. DG>>и вторая модель более лаконично описывает поведение данного кода, но требует более сложных понятий — в данном случае, требуется понятие не атомарности запроса (уже в процессе выполнения запроса мы можем получить ответ) S>Вторая модель плоха ещё и тем, что она непригодна для описания примеров, хоть чуть-чуть отличающихся от приведённого: S>
S>class Server
S>{
S> public int Ping(Action<int> pong)
S> {
S> return pong();
S> }
S>}
S>class Client
S>{
S> static public int Pong()
S> {
S> return 42;
S> }
S> static void Main()
S> {
S> var server = new Server();
S> var r = server.Ping(Pong);
S> }
S>}
S>
S>Кто здесь запрос, а кто ответ?
асинхронная пара Ping/Pong с последующей синхронной парой Pong/Pong.return
S>
S>class Server
S>{
S> public Server(Action<int> pong)
S> {
S> _pong = pong;
S> }
S> public int Ping()
S> {
S> return pong();
S> }
S>}
S>class Client
S>{
S> static public int Pong()
S> {
S> return 42;
S> }
S> static void Main()
S> {
S> var server = new Server(Pong);
S> var r = server.Ping();
S> }
S>}
S>
S>А здесь?
тоже самое: асинхронная пара Ping/Pong и синхронная пара Pong/Pong.return
изменилась лишь структура связей (в первом случае, сервер был независим от client-а, сейчас он стал зависимым.
S>Но причем же тут побочный эффект? Где побочный эффект у OrderBy? Где то, что соответствует определению побочного эффекта в OrderBy? Без согласования терминов ответить однозначно невозможно.
согласовывать необходимо сначала задачи, потом условия(границы) и только потом термины.
можно долго согласовывать термин "маленький", но без задачи и условий — это будет не о чем. и тоже самое с большинством других терминов.
S> Ведь DarkGray называет побочным эффектом просто отсутствие стабильности сортировки.
из эквивалентности кода следует, что и проблемы эквиваленты.
mutable-программу можно один в один переписать в immutable (в чисто функциональный подход), когда каждая функция заменяется на такую же (но чистую), берущую весь мир и возвращающую весь мир. при этом побочный эффект из mutable-программы в один в один перейдет в побочный эффект функций в immutable-программе
побочный эффект появляется при решении задачи:
возможность вызывать только тот код, который необходим,
или другими словами:
возможность переставлять функции в коде,
заменять функцию на ее значение и т.д.
и соответственно утверждается, что побочным эффектом называется один из видов херотени, которая мешает выполнять эти операции
возьмем код:
class C
{
public int X = new Random().Next();
public int Y = 0;
}
int F1(int y)
{
c.X++;
return y - c.X + c.Y;
}
int F2(int y)
{
c.Y--;
return y + c.X + c.Y;
}
int F0(int y1, int y2)
{
return y1 + y2 + (c.X < 0 ? -c.X : c.X);
}
static C c = new C();
void main()
{
var x1 = F1(F2(F1(F1(F1(7)))));
var x2 = F2(F1(F1(F2(F2(24)))));
Console.WriteLine(F0(x1, x2));
Console.WriteLine(x1);
Console.WriteLine(x2);
}
можно ли здесь переставить местами или заменить на значение, хоть одну функцию? нет почему? сплошные побочные эффекты по определению
заменим на эквивалентный чисто функциональный код:
class C
{
public C(int x, int y = 0){this.X = x;this.Y = y;}
public C(){this.X = new Random().Next();}
public readonly int X;
public readonly int Y;
}
class World
{
public int y;
public C c;
}
World F1(World w)
{
C c = new C(w.c.X + 1, w.c.Y);
return new World{c = c, y = w.y - c.X + c.Y};
}
World F2(World w)
{
C c = new C(w.c.X, w.c.Y - 1);
return new World{c = c, y = w.y + c.X + c.Y};
}
World F0(int y1, int y2, C c)
{
return new World{c = c, y = y1 + y2 + (c.X < 0 ? -c.X : c.X);};
}
void main()
{
C c = new C();
var w1 = F1(F2(F1(F1(F1(new World{c = c, y = 7})))));
var w2 = F2(F1(F1(F2(F2(new World{c = w1.c, y = 24})))));
var w3 = F0(w1.y, w2.y, w2.c);
PutLine(w3.y) >>= PutLine(w1.y) >>= PutLine(w2.y);
}
можно ли в этом в чистом функциональном коде переставить местами или заменить на значение, хотя бы одну функцию? нет. почему? потому что вся таже зависимость от побочного эффекта
единственная разница этого кода от предыдущего, что в предыдущем коде зависимость по побочному эффекту между x1 и x2 была неявной для ЯП и программиста (и ее необходимо было восстанавливать из кода), а здесь эта зависимость записана явна.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Формально, samius это вывеска ...
I>Хорошо, формальная вывеска, ответь пожалуйста, какие из нижеприведенных идентификаторов i1, j1, i2 и j2 являются идентификаторами неизменяемых объектов?
Все являются.
Здравствуйте, igna, Вы писали:
I>В статьях про "Immutable object" или про "Неизменяемый объект" в Википедии, во всех примерах речь идет о типах, все экземпляры которых неизменяемы, хотя согласно определениям данным в начале статей i в примере ниже является неизменяемым объектом:
I>
I>int const i = 123;
I>
I>Так ли это, можно ли назвать i здесь immutable?
Нужно детерминировать понятия "объект". Речь идет об экземпляре типа (т.е. объекте в терминах ООП), просто о некой сущности или еще о чем-то. Приведенный пример выдает своим синтаксисом тот факт, что речь идет о C#. Так что будем понимать под объектом — экземпляр некоторого типа в C#.
В такой постановке вопрос является некорректным, Так как:
1. В C# нет средств обеспечения неизменяемости для отдельных объектов.
2. Описанное выражение является константой, а константы в C# заменяются их значениями в местах применения.
Правильно будет говорить о неизменяемых типах. Неизменяемым типом являются любой тип значение полей экземпляра которого нельзя изменить после создания экзепляра.
Все встроенные типы (за исключением грязных хаков, которые не стоит брать в рассчет) обладают этим свойством хотя бы потому, что не имеют ни одного поля (являются встроенными). Исключением является тип string. Но для него незменяемость гарантируется спецификацией и обеспечивается реализацией.
Таким образом ответ таков. "int const i = 123" не является объектом, а является константным значением (или его именем, если угодно).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
S>Нет никакой точки зрения. Есть язык с платформой. Они определяют некоторую математическую модель. S>Рассуждения о том, что происходит за пределами этой модели, лишены смысла.
ты ставишь всё с ног на голову.
сначала есть модель, которой мы хотим оперировать, и только потом появляется язык, который нам помогает этой моделью оперировать.
при этом модель самого конкретного языка нас интересует вообще постольку поскольку.
если необходимо, чтобы с точки зрения языка было необходимо, чтобы переменная была не отличима от объекта, то приходится к разрабам языка и говорится: хочу, и они это обеспечивают.
S>Мы говорим о программировании — нас интересует только программа. S>Поэтому когда мы говорим об отношении эквивалентности — мы говорим об отношении, выраженном в терминах той же математической модели. То есть, к примеру, булевой функции двух аргументов.
тогда необходимо обосновать что это достаточно для решения реальных задач. а то иначе это напоминает анекдот, что я здесь ищу, потому что здесь светлее.
на реальных задачах всё очень не просто с идентичностью, а ты сейчас утверждаешь, что готов решать только задачи, где с идентичностью всё ясно. но тогда возникает вопрос, а кто будет и как решать остальные задачи?
возьмем, как пример анонимный чат — там всё еще как-то понятно с точки зрения идентичности сообщений, но с идентичностью субъектов, которые эти сообщения постят — всё очень и очень непросто. но ведь необходимо и эту задачу уметь решать.
или, например, возьмем машину — например, до какой степени машина идентична сама с собой по времени? по какому свойству определяется идентичность? по цвету, по номеру, по царапине на крыле?
или есть даже брать чисто программисткие заморочки — объект хранящийся в базе, он же на сервере, а потом на клиенте — это один и тот же объект? или это три разных?
и т.д.
и на всё это ответ один:
идентичность (и эквивалентность) имеет смысл только с точки зрения конкретной задачи с точки зрения конкретного набора операций и с точки зрения заданного набора объектов.
и соответственно, следствия:
1. два объекта могут одновременно быть эквиваленты (и не эквиваленты)
2. эквивалентность сама по себе нафиг не нужна, и не надо ее вводить, если она не требуется для задачи.
DG>>они эквиваленты лишь с точки зрения небольшого кол-ва операций над ними. DG>>например, с точки зрения компилятора, resharper-а и т.д. — они не эквиваленты, и можно привести примеры когда эта эквивалентность нарушается с их точки зрения. S>Нас не интересует точка зрения решарпера, компилятора, и прочих средств, не имеющих отношения к абстрактной машине, на которой работает программа.
S>>>И вы точно так же не сможете различить их ни в какой функции Compare(x, y).
DG>>если допустить, что ты говоришь правду, что это алиас для x.y.z, то следующий код должен выдать true(или 0), а это не так DG>>
DG>>значит это alias для чего-то другого, или a, вообще, не обладает семантикой алиаса S>Да ладно! Неужто не выдаёт 0? S>А по мне так должен выдавать. Компилятора плюсов под рукой нету. Открой же тайну — как ты определил x.y, и Compare, чтобы нарушить эквивалентность?
вот так, например:
struct X;
struct Y
{
Y(int z):z(z),x(0){}
int z;
X*x;
Y& operator = (const Y&y)
{
Y** py = reinterpret_cast<Y**>(x);
py[0] = new Y(120);
return *this;
}
};
struct X
{
X():y(*new Y(10)), y1(11)
{
y.x = this;
}
Y& y;
Y y1;
};
int _tmain(int argc, _TCHAR* argv[])
{
X x;
int&a = x.y.z;
std::cout << a << ", " << x.y.z << std::endl;
x.y = x.y1;
std::cout << a << ", " << x.y.z << std::endl;
return 0;
}
MS VC выдает
10, 10
10, 120
S>Я уже обосновал. Отложу продолжение разговора вплоть до написания функции compare, которая отличает a1 от a2. Или хотя бы a от x.y.z.
Здравствуйте, DarkGray, Вы писали:
DG>следующий вопрос задаю чисто с точки зрения разбора каких-то вырожденных ситуаций.
V>>Без сущности "переменная" ООП даже не взлетит. DG>что есть в данном случае "переменная"? это синоним одного из терминов "память", "внутреннее состояние" или "ссылка"? или что-то еще?
Это синоним слота памяти. По-определению переменная — это именованный адрес, т.е. известный во время компиляции, и доступный в виде некоего удобного программисту символа.
Не против, если я так же отвечу остальным высказываниям вокруг этого вопроса, чтобы не размазывать по ветке? Спасибо.
Я, конечно, догадываюсь, откуда ноги растут у утверждения, типа в "настоящем" ООП в переменной (т.е. по известному адресу времени компиляции) может храниться только ссылка на объект, но не боже упаси сам объект, а это, якобы, будет уже не объект, а некое "значение". Спасибо Java и дотнету, прям низкий поклон... Не согласен. Мы имеем полное право размещать объекты по известным адресам времени компиляции, так же как и по неизвестным, т.е. выделяя память для них динамически. Почему объект вдруг должен перестать быть объектом только из-за факта, что мы знаем его фактический адрес на момент компиляции — самостоятельно понять не могу, а вразумительного объяснения столь загадочной точки зрения пока не увидел.
Так же, как упоминал про способы адресации. Способ адресации — это просто способ "добраться" до цели, и этих способов может быть несколько. То, что целью является объект, не влияет каким-то загадочным способом на разновидности адресации, бо самим этим способам характеристика цели до фени: объект там, или просто набор байт...
Ну и вопросы, типа не путаю ли я тем самым (т.е. оперируя способами адресации) ООП и "просто" ЯП вводят меня, признаюсь, в глубокий ступор...
Здравствуйте, vdimas, Вы писали:
V>Э нет, переменная — это "инструкция" высокоуровневого ЯП. Программу мы пишем не для времени компиляции, а именно для рантайма. И переменная — это инструкция управления/распределения памяти, где само фактическое распределение выполняется опираясь на типы значений, которые необходимо разместить в некоей памяти. И не надо пытаться строить такую невинность, что это всё далекие абстракции, которыми мы оперируем и не интересуемся реально происходящим. Дудки. Ты именно всегда непосредственно указываешь для переменной область памяти, в которой ее необходимо распределить: будь то глобальная область памяти, локальная или в области памяти, занимаемой объектом (т.е. в виде поля другого типа). Абтрагирование от конкретики происходит только на уровне типов, т.е. мы абстрагируемся лишь от размеров памяти, требуемых для значений (и как побочный эффект — защищаемся от неверной интерпретации этой памяти), больше ни от чего. Остальное мы указываем очень даже конкретно из расчета как нам конкретно надо, чтобы оно работало в рантайм.
Это неконструктивная позиция.
Потому, что вот я указал очень конкретно, где что размещать:
public void Test()
{
int i = 42;
Где у нас i? В стеке?
Как бы не так! Потому что дальше (через 100 строк) я пишу:
Здравствуйте, Sinclair, Вы писали:
S>В это понимание совершенно не обязаны входить заблуждения типа "статическое поле — это прямой адрес, а экземплярное — это адрес + смещение". Семантика полей в дотнете такова, что статическое поле хранит ровно одно значение в пределах домена, а экземплярное — по значению на каждый экземпляр. Всё. Каким конкретно образом обеспечивается доступ к этим полям — знать необязательно. А зачастую ещё и противопоказано, т.к. провоцирует на написание implementation-dependent кода.
Извини, коллега, но ты как с другой вселенной. Я прекрасно понимаю, о чем ты, но не верится, что об этом можно вот так всерьез на весь интернет. Особенно когда постоянно приходится работать над быстродействием дотнетных программ. Я понятия не имею, чем вы там на работе занимаетесь, но сколько видел или участвовал в проектах... так вот, "абстрактные" программисты, не понимающие суть происходящего, для более-менее серьезных проектов банально профнепригодны. Не нужны.
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Здравствуйте, gandjustas, Вы писали:
V>>>>>Это верно в той области ПО, для которой эффективность не является конкурентным преимуществом. Например, для заказного ПО, там же никакой конкуренции... Нужна лишь некая "достаточная" производительность. G>>>>Да-да-да. Забавная байка. У тебя есть сведения о корреляции производительности и продаж для определенного класса программ? V>>>Есть. G>>Показывай.
ГВ>А тебе ключи от сейфа не надо? Упрись, там и разберёшься, что на что влияет. Просто прими как факт, что есть такие предметные области, где 30 микросекунд latency — "слив зощитан", а 1,5 микросекунды — топ продаж. Но вообще, тебе о том знать не надобно, так оно проще: я ничего не имею против того, чтобы абсолютное большинство озабочивалось latency, когда оно превысит сотни миллисекунд.
Не думаю что слово "коробочный" к такому ПО применимо.
V>>>>>А в коробочном ПО в реальности бывает так, что профайлер показывает до 30% затрат на всего одну из самых затратных операций, но она никак не оптимизируема, всё, упёрлись в предел. Зато остальное можно подтянуть, то самое, которое 1-2% каждое в среднем, но примерно вдвое общую эффективность поднять, подняв каждую из мелочей многократно. Это из реальной практики... Для каждого такого случая нужны банально идеи, бо показания профайлера тебе код не напишут. G>>>>А ты вообще прочитал то что я процитировал? В 5 пункте fixable слово видел? V>>>И? G>>Прочитай еще раз
ГВ>
If you did not meet your goal, use tools to discover what the worst-performing fixable thing is, and fix it.
ГВ>"Если у вас что-то работает плохо — поправьте, что получится (именно так надо переводить fixable), используя подходящие средства." Бу-га-га! Офигительной глубины совет.
И он, сука, работает. Я тут недавно консультировал коллег по вопросам производительности. Они полмесяца тыкались не зная в чем проблема, потом я показал как в их случае надо мерить. Вот померили и сразу нашлись узкие места. Которые поправили за считанные дни.
Любая попытка улучшить производительность должна начинаться с замеров и устранения узких мест.
Тут же каждый второй гуру говорит что нужны тайные знания, а на практике 99% производительности вытягивается именно так. А только 1% требует "щаманства".
V>>>>>Есть еще момент: эффективность не всегда определяется пропускной способностью, зачастую идет требования минимизации latency (у нас по работе, например), а в этом деле, когда речь идет о единицах микросекунд, профайлерами уже и близко не пахнет. G>>>>А чем пахнет? ты ведь как-то меряешь этот самый latency или ты по коду пытаешься его угадать? V>>>Специальные тесты на производительность нужны, с максимальной изоляцией, чтобы минимизировать паразитную постоянную составляющую измерений. G>>То есть ты все равно меряешь.
ГВ>Замеры замерам рознь. Я тебя уверяю, цифры, которые выдаёт профайлер в синтетических тестах, далеко не всегда подходят для выводов о производительности в реальных условиях.
Отсутствие каких-либо цифр не лучше. Попытка делать хоть какие-то выводы в таком случае — шаманство.
Здравствуйте, gandjustas, Вы писали:
ГВ>>Молодцы. Только это никак не отменяет того, что приведённая цитата содержит банальность. G>Именно, но даже эту банальность не все знают и понимают.
А... Ну да, в общем. Извини, я не ожидал, что всё вокруг настолько плохо, что даже банальности не всем понятны, и эта непонятливость настолько велика, что ты её автоматически переносишь на любых оппонентов.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
S>Ты ведь где-то поднабрался истинного смысла? А все остальные юзают определения по-старинке, без конструктивизма. Займись изданием букваря, что-ли. Ну или дай свои определения тем терминам, что ты используешь. А те что в википедии — они не про то, о чем ты хочешь поведать.
развешивание ярлыков, и выяснение при каких условиях темно-красный можно называть черным, а голубой — белым — это не ко мне, это к википедии, в букварь и т.д.
я готов поговорить, какие явления есть (а не определения), при каких условиях они проявляются, как они помогают (или мешают) решать те или иные задачи.
есть явление "побочный эффект" которое мешает решать ряд задач при трансформации кода.
примеры которые показывают это явление — я привел, если ты имея эти примеры и определение из википедии не можешь восстановить у себя в голове образ этого явления, то задай вопросы об этом — это конструктивный разговор.
а разговоры о терминах — это всегда деструктивный разговор, не создающий нового знания.
Здравствуйте, vdimas, Вы писали:
V>Гы, поднимись в определениях на один уровень раньше и посмотри, что есть вычислимая ф-ия. V>Своими словами — это та, для которой существует конечная программа в терминах пошаговых инструкций над идеальной машиной (с бесконечной памятью).
МТ эквивалента лямбда-исчислению, блок схемам и ЧРФ.
Так что можно считать вычислимой функцией ту, которую можно записать в виде ЧРФ.
Вычислимость — свойство самой функции, императивность — свойство записи алгоритма вычисления.
V>Ленивость — это изолированный мини-автомат, это та самая классическая ф-ия с памятью, которая и зовется автоматом. Именно ленивость позволяет Хаскелю упорядочить последовательность вычислений, делая их детерминированными, т.е. это именно инструмент детерминированной реализации программы по вышестоящему императивному ТЗ.
Прямо немерянное количество заблуждений в одном предложении.
1) С чего это ТЗ императивно? Как раз хорошее ТЗ максимально декларативно. То есть не описывает конкретных шагов для получения результата.
2) С чего это ленивость- "автомат"? Может у них какие-то общие свойства есть?
V>Т.е. таки ленивость не то, что означает императивность, она именно для возможности привнесения императивности и существует
Опять какой-то бессвязный набор слов.
Императивный алгоритм — тот который задает последовательность шагов, изменяющих некоторое состояние для достижения результата. Любой императивный алгоритм можно представить в виде структурированой блок-схемы.
Ленивость заключается в том что агрументы функции вычисляются не при вызове, а при обращении. Это как раз дает непостоянную последовательность вычисления. То есть как раз в виде блок-схемы записать не получится.
V>Это такой комбинатор, для которого можно установить необходимый и достаточный порядок вычисления аргументов вместо произвольного.
То есть ленивость таки не соответствует фиксированному порядку, а значит не является императивным.
V>где требуется детерминированная последовательность операций
Требуется она в одном случае — при общении программы с внешним миром.
V>В общем, иначе было бы гораздо сложнее реализовать исходное императивное ТЗ на чистом ФП, если бы не ленивость.
О чем ты? Бери F# и Haskell, покажи в чем леность помогает общаться с внешним миром.
И снова напомню что хорошее ТЗ максимально декларативно.
V>Пришлось бы бороться с комбинаторным взрывом при вычислении (в общем случае рекурсивном) всех аргументов всех операций. И не факт, что программа имела бы останов...
Это ты о чем вообще? ЧРФ эквивалентны блок-схемам, причем без всякой ленивости
S>>>Возникает вопрос о целеобразности такого автомата, ну да фиг с ним.
DG>>о том и речь, что все зависит от набора команд, поддержанных исполнительным механизмом (или что тоже самое, от вида исполнителя). S>Не понимаю, что такое вид исполнителя и как он меняется от изменения набора команд.
есть вид исполнителя: процессор x86,
есть вид исполнителя: реляционная субд с поддержкой sql,
есть вид исполнителя: стековая машина с модулем АЛУ и ФПУ,
есть вид исполнителя: .net,
есть вид исполнителя: .net с набором библиотек для заданной тематики,
есть вид исполнителя: haskell,
есть вид исполнителя: "человек с тремя классами образования",
есть вид исполнителя: человек-специалист в заданной тематике.
и т.д.
каждый из них обладает своим набором поддерживаемых команд, если этот набор последовательно менять (добавляя/убавляя по команде), то произойдет переход к другому виду исполнителя.
DG>>и что если не зафиксирован исполнитель (в виде поддержанного им набора команд), то делать какие-то утверждения бессмысленно, и уж тем более бессмысленно делать заявления о декларативности или императивности управляющего языка. S>И все-таки, как связана декларативность языка с исполнителем?
напрямую (и ты это увидишь, как только определение из той же вики переведешь к математическому виду)
например, для исполнителя samius конструкция "автомат из одной команды Z" есть императивная программа, которую он понимает только если рядом приложена пошаговая инструкция, как из этой конструкции перейти к поддерживаемому им набору команд, в частности, к автомату математическому классическому.
большая часть сказанного в треде воспринимается также императивно: понятно пока есть инструкция — как это понимать; при наличии малейших отклонений в условии — ступор и выдача ошибки.
не делает видимых попыток перехода к декларативному мышлению: фиксирование требований к результату с последующим выбором наилучших инструментов для достижения поставленной цели.
Здравствуйте, DarkGray, Вы писали:
S>>Вот тебе тривиальный пример { 1, 1, 1, 1, ... }
DG>и каким свойством эта штука не обладает, по которому его можно исключить из класса множеств?
DG>например, берем одно из определений множества DG>
DG>Множество есть совокупность различных элементов, мыслимая как единое целое
DG>элементы есть, совокупность есть, единое целое тоже есть — значит множество.
Здравствуйте, DarkGray, Вы писали:
S>>Непонятно, что ты собрался фальсифицировать в определении отображения. Ведь никаких утверждений определение само по себе не дает.
DG>есть (как минимум) два варианта как делать конструирование перебора множества: DG>1. можно сначала взять все функции F(Nat)->элемент множества, а потом выбрать из них ту, для которой доказано, что эта функция перебирает все элементы множества, что для сложных случаев будет нетривиально. при этом доказательство обязано быть полным, потому что если оно будет неполное, и ошибка все-таки просочиться и функция F все-таки какие-то элементы забывает, то это уже поймать нельзя будет. DG>2. можно идти от обратного: взять функции F'(элемент множества)->Nat и выбрать из них те, которые непротиворечивые (не переводят два элемента множества в одно число). здесь можно использовать неполные доказательства, потому что если ошибка все-таки есть и мы ее упустили при доказательстве, то она всплывает при исполнении.
DG>и соответственно, второй вариант предпочтительнее
DG>или другими словами: нельзя обеспечить, что не было ошибок, но можно обеспечить, чтобы ошибки (если они все-таки есть) были явные, вместо неявных.
1. Кто придумал что функция должна перебирать все элементы множества?
2. Ты вообще мои ответы читаешь перед тем как скипаешь неудобные тебе вещи? Еще раз. Функцией F'::X->Nat невозможно задать последовательность с повторяющимися элементами. Прежде чем скипать, попытайся поразмыслить над этим.
З.Ы. Не писал я что ты глупый. Я писал что не могу понять о чем ты пишешь, когда пытаюсь сопоставить используемые тобой термины с известным мне толкованием их. Вот сейчас я не пойму, что ты называешь последовательностью, если допускаешь что в ней не могут повторяться элементы. И что ты называешь множеством, если допускаешь что в нем элементы могут повторяться.
S>>2. Ты вообще мои ответы читаешь перед тем как скипаешь неудобные тебе вещи? Еще раз. S>>Функцией F'::X->Nat невозможно задать последовательность с повторяющимися элементами. Прежде чем скипать, попытайся поразмыслить над этим.
DG>следующий вариант задает отображение с повторяющимися элементами DG>
DG>F'(false) -> i, where 0<=i<=2
DG>F'(true) -> i, where 3 <= i < = 5
DG>
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, vdimas, Вы писали:
V>>есть только одна эта задача на своем уровне, которая понятия не имеет о вызовах других printf(). И есть некий низлежащий слой ОС. И эта задача вполне может быть выполнена без побочных эффектов на своем уровне, передавая данные "куда-то дальше"... S>Нет, она не может быть выполнена без побочных эффектов. Она целиком и полностью опирается на определённое поведение разделяемого состояния.
+1 (*) V>>В чистых функциональных языках тоже ведь как-то ввод-вывод делают, просто разграничивают, что это делает "кто-то другой" через библиотеки. S>А вы поинтересуйтесь, как же так в чистых функциональных языках делают ввод-вывод. Там ведь нет ничего сложного — просто вместо неявного состояния вычислителя, на котором работают императивные программы, вводится явное состояние аргумента. Грубо говоря, вместо void printf(...) у нас появляется S>
S>Console printf(this Console in, String text);
S>
S>Сама printf здесь не имеет побочных эффектов — её можно вызывать на одном и том же аргументе сколько угодно раз, и результат всегда будет одинаковым.
Если она не имеет побочных эффектов, значит в консоли ничего не должно измениться. Вывод в консоль есть побочный эффект. см (*). Даже если значение Console, возвращаемое printf, полностью инкапсулирует "состояние консоли", все равно где-то должна остаться информация о том что нынче актуально состояние консоли, описанное именно в последнем экземпляре. И обновление этого знания будет являться побочным эффектом.
S>Чтобы задать порядок, надо явно писать S>
S>console.printf("Hello").printf("World")
S>
Да, Console printf(this Console, String) — это способ упорядочить выполнение функций с побочным эффектом, но не избавиться от побочнго эффекта.
Побочный эффект можно отложить, что и делается в хаскеле. Следующая функция printf не содержит побочных эффектов. Побочные эффекты будет содержать результирующий Action
В сочетании с необходимостью упорядочивать побочные эффекты мы как раз и получаем аналог хаскелевского вывода
class World {} // весьма топорно, но пойдет для примера.
Func<World, World> printf(String str)
{
return world => { Console.WriteLine(str); return world; };
}
// или чуть ближе к putChar:: Char -> IO()class Unit {};
Func<World, Tuple<Unit, World>> printf(String str)
{
return world => { Console.WriteLine(str); return Tuple.Create(new Unit(), world); };
}
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Sinclair, Вы писали:
V>>>есть только одна эта задача на своем уровне, которая понятия не имеет о вызовах других printf(). И есть некий низлежащий слой ОС. И эта задача вполне может быть выполнена без побочных эффектов на своем уровне, передавая данные "куда-то дальше"... S>>Нет, она не может быть выполнена без побочных эффектов. Она целиком и полностью опирается на определённое поведение разделяемого состояния.
V>Это только у нас в голове так, согласно доке по консоли.
Т.е. если доку не читать, то побочных эффектов в printf не будет?
V>Дык, тело сишной printf тоже не имеет никаких побочных эффектов, является полностью реентерабельной. Если бы были побочные эффекты именно внутри кода printf, она не была бы реентерабельной и многопоточной. И да, в printf таки подается FILE (просто в той перегрузке, в которой не подается, используется глобальная переменная). И отличие в Хаскеля лишь в том, что IO-тип Console не надо возвращать обратно как результат ф-ии, бо это лишь частное требование для механики монады IO, которая не нужна в C++.
printf консоль портит? Портит. А значит побочный эффект присутствует. putChar консоль портит? Нет. Вот в этом и отличие от Хаскеля.
S>>Чтобы задать порядок, надо явно писать S>>
S>>console.printf("Hello").printf("World")
S>>
V>Вооот... мы дошли до цепочек вычислений в ф-ом программировании, через механизм вложенных вызовов ф-ий, мне даже не пришлось 10-й раз намекать, как для случая РА. Чем не императив? ИМХО, только точкой зрения на происходящее.
f(g(x)) тоже императив?
V>>>При том, что изменяющееся состояние приписали "императивному" исторически. Императивность — это последовательность инструкций, факт обязательности побочных эффектов не является неоспоримым. S>>Вы, я вижу, не понимаете простой вещи. Если нет побочных эффектов, то "последовательность" инструкций — фикция.
V>Это ес-но, речь шла о том, где заканчивается декларативное и начинается императивное. Твои побочные эффекты могут быть нам недоступны, т.е. не влиять на элементы нашей программы, примерно как в монаде IO. В чем тогда отличие якобы декларативного Хаскеля в случае этой монады, и императивной программы, которая использует только "чистые" ф-ии и процедуры, не изменяющие неявно состояния нашей программы?
В том что программа на Хаскеле описывает результат. А императивная программа описывает последовательность действий.
S>>Единственный способ принудить инструкции исполняться последовательно — ввести зависимость их друг от друга. В императивном программировании зависимость вводится через побочные эффекты.
V>Первое предложение ты написал поторопимшись. У нас уже есть низлежащая аппаратура, которая близка по принципу работы машине Тьюринга, поэтому последовательность инструкций мы имеем как вычислительный базис. Отличие ф-ых языков от императивных в том, что ф-ые скрывают от программиста внутреннюю работу с состоянием, т.е. на уровне пользовательской программы побочных эффектов НЕТ. Я же привел printf не случайно, показав точно такой же случай, что на уровне пользовательской программы нет никаких побочных эффектов. Я понимаю, что тебе сразу захотелось полезть куда-то внутрь, чуть ли не до самой машины Тьюринга и показать мне, что таки состояние есть у консоли "где-то там унутрях"... но это очень толсто, коль этот случай сравнивался с точно таким же аналогичным из ФЯ...
И зачем по-твоему вызывать из C++ printf если побочных эффектов у него нет и он ничего не возвращает/вычисляет? Почему бы его просто не выкинуть из пользовательской программы?
V>В общем, я еще с самого начала предупредил, что тема иммутабельности и границ императивности — скользкая. Много холивара и условностей, а львиная доля любой императивной программы — абсолютно чиста с т.з. побочных эффектов над доступными примитивами программы. Сказать, что я заведомо определился с какой-то точкой зрения не могу. В разных спорах участвую с разных сторон. Интересны сугубо аргументы. Бо сдается мне, что прямо на сегодня в этих понятиях слишком много религиозного и зависимости от точки зрения и глубины рассмотрения происходящего. А раз так, то использовать их в кач-ве аргументов следует осторожно или не использовать вообще, предпочитая обсуждать конкретику вместо приема спора, когда вопрос пытаются отнести к некоему "классу" и выстроеному последующему док-ву на принадлежности проблемы к сему классу.
Конечно, если считать printf декларативным и не имеющим побочных эффектов, а монады императивными, то тема очень скользкая.
Давай по-маленьку. Как printf влияет на результат функции, в теле которой вызывается? Как влияет putChar из Хаскеля?
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали: S>>Если она не имеет побочных эффектов, значит в консоли ничего не должно измениться. Вывод в консоль есть побочный эффект. см (*). Даже если значение Console, возвращаемое printf, полностью инкапсулирует "состояние консоли", все равно где-то должна остаться информация о том что нынче актуально состояние консоли, описанное именно в последнем экземпляре. И обновление этого знания будет являться побочным эффектом. S>Ну, я, возможно, фантазирую, но пока что я не вижу неотъемлемой необходимости обновления этого знания — равно как и понятия "нынче".
Необходимость есть при вводе данных из консоли. А так же, если нам нужно интерактивно отображать прогресс вычислений в консоли. В таком случае нас не усроит одна результирующая версия консоли.
S>Идея примерно такая: вот, допустим, у нас есть некоторая Функциональная Программа. Она, собственно, сводится к одной мега-функции (скажем, Main) которая отображает вход на выход. S>Эта функция написана некоторым "декларативным" способом — т.е. в виде композиции некоторого набора других функций. S>Никакого "состояния" нет. S>Предположим теперь, что у нас в параметры и результаты этой функции входит некоторая структура Console, которая представляет, скажем, недо-стек строк. Т.е. pop из этого стека нельзя, можно только push, при помощи функции Console println(Console c, string s). S>И вот эту структуру Console мы протаскиваем во все вызовы всех функций, начиная с Main: S>
S>Console stdout = Main(emptyConsole, input);
S>
До сих пор все более-менее соответствует программе на хаскеле. Небольшие уточнения:
main в хаскеле обладает типом IO():
main :: IO()
тип IO() можно представить как функцию
type IO a = World->(a, World)
Таким образом, результатом "выполнения" main является функция. Слово выполнение тут неуместно, лучше сказать "построения", или даже "определения". На этапе построения результирующей функции никаких побочных эффектов не было, т.к. ничего не выполнялось до сих пор, а лишь определялась результирующая функция. Т.е. все действия с монадами, которые кое-кто считает "императивными" до сих пор точно так же не выделяли никаких побочных эффектов. Все тело функции main декларирует ее результат и только его.
Далее, исполнитель программы на хаскеле берет результирующую функцию и подает ей на вход World.
imperativeRun :: IO() -> World -> Int-- это я только что выдумал
Вот тут-то и появляется мир с его состоянием, которое обновляется должным образом в процессе выполнения итоговой функции. Трюк в том, что это происходит за пределами программы на хаскеле.
S>Внутри Main могут быть всякие ветвления, рекурсия, и прочее. Каждая из функций может чего-то записывать в консоль (скажем, отладочный вывод).
да, ветвления, рекурсия и прочее. Но каждая из функций, к которым обращается main, не пишет и не читает. Они возвращают функции, которые при выполнении будут писать и читать. А main из этих функций комбинирует свой результат.
S>Благодаря отсутствию побочных эффектов, порядок вычисления разных веток нам не важен. В том числе, параллельно могут существовать несколько версий консоли, отличающихся содержанием.
На этапе построения результата main побочных эффектов нет. Но порядок их выполнения при выполнении результирующей функции нам важен. Этот порядок обеспечивается композицией функций, из которых строится main. Они представляют собой конвейер по надругательствам над миром. Тут уже не важно, считать ли мир изменяемым, или считать что каждая функция при выполнении создает новую копию мира и где-то есть указатель на текущий мир. Важно что конвейер обеспечивает точный порядок приложения функций к миру.
S>К окончанию программы у нас останется ровно одна версия консоли — та, которая вошла в результат. S>Её мы и будем трактовать как "настоящую"
Если бы программе не нужно было бы работать в режиме диалога с миром, то такая модель могла бы работать.
А в хаскеле так: к окончанию декларативной программы на хаскеле у нас появляется программа для вычислителя. Программа для вычислителя императивна и может работать с изменяющимся миром/консолью.
S>А рассуждения про адреса и фреймы стеков оставьте для тех платформ, где они являются терминологией и признанными абстракциями (например, для x86-ассемблера)
ты постоянно делаешь одну и тужу ошибку — ты постоянно забываешь, что ты общаешься на ЕЯ.
а ЕЯ сам по себе очень противоречив ради повышения эффективности общения, это в частности проявляется, что одни и те же слова используются для обозначения совершенно разных вещей.
когда vdimas говорит про stack — он имеет ввиду, что при описании семантики локальных переменных (в том числе, когда есть рекурсия) необходимо в любом случае вводить структуру данных LIFO (которая и есть stack-структура данных).
ты же отвечаешь про stack, как про конкретную штуку из реализации конкретных ЯП, которые в данном случае вообще никакого отношения к дискуссии не имеют.
зы
перед каждым ответом советую сначала определиться, какие слова каким терминам соответствуют, и только отвечать; а не брать первое подходящий термин и отвечать именно на него.
S>Благодаря этой отдельности я могу следить, на чём основаны те или иные предположения, и будут ли они оставаться справедливыми при замене того или иного уровня абстракции.
так тебе vdimas верно и говорит, что единственно инвариантным утверждением при переходе между разными уровнями абстракции остается то, что переменная использует локальную адресацию с семантикой address := F(context, local-address), причем address — это тоже локальный адрес, но уже в каком-то другом более большом контексте .
если брать переменную из функции, то в качестве context-а будет stack-frame функции. при исполнении этот stack-frame может отображаться на stack исполнения, на регистры или на heap(отдельный объект), если используется замыкание.
если брать static переменную, то в качестве context-а будет сборка.
если брать переменную из объекта, то в качестве context-а будет сам объект
Здравствуйте, DarkGray, Вы писали: DG>пока не показано, как это связано с реальностью, это религия.
Я вам советую по возможности избегать математики. Там везде сплошная религия. Берут, скажем, набор требований, и называют конструкцию, которая этим требованиям удовлетворяет, полем.
Ни тебе связи с реальностью; ни тебе доказательства того, что без дистрибутивности поле не работает. Нет чтобы ввести понятие "частичной дистрибутивности", применимой не во все моменты времени.
А то и вообще — как начнут выписывать аксиомы типа "через точку можно провести ровно одну прямую, параллельную данной", опираясь на понятие прямой, которого в реальности не существует. Мы же хорошо знаем, что реальные прямые всегда хоть чуточку, но кривые.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>разделяющие их на разные классы эквивалентности с точки зрения кого? и с точки зрения каких операций? это был ключевой вопрос в абзаце на который ты отвечал.
Нет никакой точки зрения. Есть язык с платформой. Они определяют некоторую математическую модель.
Рассуждения о том, что происходит за пределами этой модели, лишены смысла.
Мы говорим о программировании — нас интересует только программа.
Поэтому когда мы говорим об отношении эквивалентности — мы говорим об отношении, выраженном в терминах той же математической модели. То есть, к примеру, булевой функции двух аргументов.
DG>они эквиваленты лишь с точки зрения небольшого кол-ва операций над ними. DG>например, с точки зрения компилятора, resharper-а и т.д. — они не эквиваленты, и можно привести примеры когда эта эквивалентность нарушается с их точки зрения.
Нас не интересует точка зрения решарпера, компилятора, и прочих средств, не имеющих отношения к абстрактной машине, на которой работает программа.
S>>И вы точно так же не сможете различить их ни в какой функции Compare(x, y).
DG>если допустить, что ты говоришь правду, что это алиас для x.y.z, то следующий код должен выдать true(или 0), а это не так DG>
DG>значит это alias для чего-то другого, или a, вообще, не обладает семантикой алиаса
Да ладно! Неужто не выдаёт 0?
А по мне так должен выдавать. Компилятора плюсов под рукой нету. Открой же тайну — как ты определил x.y, и Compare, чтобы нарушить эквивалентность?
DG>пожалуйста. DG>для: DG>
DG>int& GetValue(){int x = 5;return x;}
DG>
DG>следующие два варианта кода обладают разным поведением. один периодически падает, другой нет. DG>
DG>int a = GetValue();
DG>
DG>
DG>int &a = GetValue();
DG>
DG>ты же не говорил, что конструкционную семантику ты выбрасываешь, которая отличается для переменной и ссылки. DG>и что ты считаешь их эквивалентными только с момента их создания.
Конечно же только с момента создания. Я привёл пример кода, определяющего a1 и a2 некоторым конкретным образом. Я не обещал того, что int& вообще всегда будет вести себя всегда как int. Утверждение об эквивалентности типов — совсем другое.
DG>
DG>int a1= 1;
DG>int &a2 = a1;
DG>
DG>или первую строку можно закоментировать, при этом вторая строка со ссылкой не скомпилится, а если закоментировать вторую, то всё будет нормально.
Я не обещал эквивалентности строчек в программе. Я обещал эквивалентность имён a1 и a2, при условии, что имя a2 определено как ... & a2 = a1.
DG>опять же когда ты говорил про эквивалентность, ты не говорил, что ты выкидываешь операции рефакторинга над этими сущностями.
"Операций рефакторинга" над этими сущностями не существует. Операции рефакторинга производятся над программой, а не над тем, с чем она работает.
Если хочется позаниматься ерундой, то можно сразу же сказать, что a2 ни разу не эквивалентно a1, потому что любая утилита текстового сравнения отличит "a1" от "a2". Решарпер и компилятор по отношению к a1 и a2 выступают в роли утилит текстового сравнения.
DG>вообще-то обсуждали эквивалентность. вопрос идентичности появился чуть позже
Когда мы говорим "а это то же самое, что и б", мы, как правило, имеем в виду идентичность.
Тем не менее, даже если хотелось пообсуждать эквивалентность, то вопрос сравнения стоит на первом месте и в ней.
DG>если обсуждается вопрос: эквиваленты ли операции присвоения значения и получения значения из переменных a1, a2 операциям присвоения и получения значения из объектов Variable/RefVariable? то здесь нет нужды еще вводить идентичность Variable/RefVariable
Этот вопрос не обсуждается. Обсуждается вопрос эквивалентности имени переменной и самой переменной. Он плавно перетёк в вопрос эквивалентности ссылки на переменную в С++ и "самой" переменной.
В качестве иллюстрации был приведён якобы эквивалентный код, который не является эквивалентным. И для опровержения этой эквивалентности мне не нужно заниматься трюками вроде привлечения решарпера, раскапывания исходников компилятора, комментирования разных фрагментов кода.
Мне достаточно написать простую функцию, которая работает для одного из этих фрагментов кода, и попросить написать такую же функцию для другого.
DG>вот если перейдем к вопросу обсуждения эквивалентности идентичности для одной пары и для другой, тогда стоит будет ввести.
S>>Я честно предупредил, что будет после того, как вы её добавите. Фактически, предлагаемые вами Variable и RefVariable могут "выглядеть одинаково", при условии, что мы не смотрим на них слишком внимательно (например, пользуемся только GetValue и SetValue). При этом они, очевидно, не "являются одинаковыми" в вашей терминологии. В отличие от имён a1 и a2 в моём примере, которые принадлежат одной и той же переменной.
DG>все эти утверждения зависят от внимательности рассмотрения: и одинаковость a1 и a2, и одинаковость Variable/RefVariable, и эквивалентность переменных и объектов.
DG>и стоит обосновать почему твой взгляд стоит считать самым внимательным.
Я уже обосновал. Отложу продолжение разговора вплоть до написания функции compare, которая отличает a1 от a2. Или хотя бы a от x.y.z.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>> В головах остальных людей голоса дают такое определение отображения:
DG>почему в головах этих остальных людей определение функции вместо определения отображения? DG>http://en.wikipedia.org/wiki/Binary_relation
Кручу-верчу, запутать хочу!
Почему в твоей голове вместо определения отображения определение отношения?
Здравствуйте, DarkGray, Вы писали:
S>> В головах остальных людей голоса дают такое определение отображения:
DG>почему в головах этих остальных людей определение функции вместо определения отображения? DG>http://en.wikipedia.org/wiki/Binary_relation
Не вместо, а вместе. Функция, отображение, операция, оператор — это синонимы.
А вы зачем-то вместо определения отображения приводите определение отношения. Когда уже вы прекратите этот бессмысленный троллинг?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>зы DG>>напомню, что ООП не требует, чтобы все сообщения обязаны доходить до адресата без потерь. S>Я напомню свой вопрос про машину Тьюринга, оборудованную ненулевым количеством ошибок. Подумайте на досуге, зачем вам нужно такое ООП, в котором сообщения не обязаны доходить до адресата, и будет ли в нём хоть что-то, что не моделируется "обычным" ООП.
потому что ни любая реальная программа на длительном периоде (или распределенная программа даже на коротких периодах), ни реальная жизнь — этой идеальной машине тьюринга с бесконечной лентой и с бесконечным временем с идеальной устойчивости к ошибкам не соответствует.
на практике: время конечно, память конечна, есть потери внутри программы, есть потери в реальности, есть потери на стыке между программой и реальностью.
и если использовать идеальную модель в которой ничего этого нет, то не получится ни описывать, ни решать проблемы и задачи, которые в действительности происходят в программах и в реальной жизни.
а цель модели именно в этом, а не в чем-то другом.
S>и будет ли в нём хоть что-то, что не моделируется "обычным" ООП.
будет. как минимум, появляется знание — какие алгоритмы можно использовать, а какие нельзя.
например, с точки зрения модели с потерями — нельзя использовать алгоритмы с итерационными сообщениями без синхронизации состояния между объектами (прибавь единицу, вычти пять; поверни налево, пройди два метра, поверни направо).
а как раз такими алгоритмами злоупотребляет большинство программистов, которые почему-то считают, что они находятся в идеальном мире в идеальной модели в которой ничего не теряется.
S>Прикольный поток сознания. S>1. Вообще, время у нас появляется сразу же, как только появляются понятия "раньше" и "позже".
позже/раньше -это всего лишь еще одна координата, и при этом ничего дополнительного кроме еще одной координаты не вводится.
раньше значение от 0 до 255 могло находиться в ячейке с координатами от 0 до 1петабайта,
а после введения позже/раньше — значение от 0 до 255 может находится в двухмерной сетке: по одной координате — от 0 до 1петабайта, а по другой — от 0 до 1 петатакта)
S>2. Вы по-прежнему путаете отношение идентичности с отношением эквивалентности.
я их не путаю. а знаю, что любое отношение идентичности является таковым только в небольшой локальной модельке, как только модель берется чуть шире оно сразу из отношения идентичности переходит в отношение эквивалентности.
S>3. Время совершенно не обязано быть глобальным. "Синхронизация" времени в ООП-модели выполняется только в момент обмена сообщениями. Если два объекта получают сообщения независимо друг от друга, то нельзя определить, кто из них получает что раньше. У каждого из них своё локальное время.
согласен. ну хоть какая-то неопределенность и неоднородность допускается в модели — уже хорошо.
но вот такой, например, не однозначный вопрос: допустим локальное время с точки зрения каждого объекта непрерывное.
но при этом является ли оно таковым же с точки зрения стороннего наблюдателя: как внутри системы? так и снаружи?
и что про это говорит твой канонический вариант ООП?
зы
в реальности так себя ведет sleep (или гибернейт): программа внутри слипа считает, что у нее время непрерывное, у программы снаружи слипа тоже непрерывное, но при этом с точки зрения второй программы время первой программы разрывное.
S>4. Понятие однородности времени и пространства в ООП не имеют никакого смысла, как бы красиво ни звучали эти слова. Особенно однородность относительно друг друга.
мне непонятно это утверждение.
у меня один критерий — можно ли это применить к реальности или нет.
вот твой вариант может описать ситуацию с гибернейтом, в чем там проблема? и как ее решать? или не может? если не может — значит в топку.
и нужен другой вариант ООП, для которого такие вещи имеют смысл.
DG>>вы рассматриваете ООП лишь для случая: строго однородное строго атомарное строго непрерывное пространство, S>Где вы это увидели? Никакого условия непрерывности пространства в ООП нету, как бы ни вводилось понятие пространства.
есть же, конечно. как только ты начинаешь утверждать, что сообщения гарантированно доходят — это вводит требование, что пространство непрерывно.
что опять же не умеет описывать поведение такой реальной штуки, как работу тонкого клиента в браузере в мобильнике.
вот для него пространство разрывное, при чем в строго определенные промежутки времени.
S>Понятие однородности я уже прокомментировал выше. DG>>условное время (в виде лишь условной последовательности сообщений), есть строго полное знание ("мир" знает всё про всех), все состояния строго однозначные (нет неопределенных состояний) S>Как раз такое время, как я описал — это самое минималистичное определение времени, при котором ООП ещё работает.
что значит еще работает? если этого нет, то какая модель это описывает? вот, например, в аналогом компьютере — нет никакой последовательности сообщений. при этом его работу какая модель описывает? и в чем ее отличие от Канонической Модели ООП с большой буквы?
S> Поверх него можно вводить более сильные модели времени — например, с глобальным временем или понятием "длительности". S>Никакого требования "мира" знать всё про всех нету — это вы придумываете что-то своё.
как только ты ввел требование, что есть единая функция идентичности в любой момент времени, ты потребовал — что мы все объекты мира можем перечислить в любой момент времени, что и означает, что "мир" знает про все объекты.
DG>>и соответственно, всех этих ограничений нет в самой модели ООП, а вы их накладываете сами. S>Вы не понимаете, что такое "ограничение", и что такое "накладывать". Вся математика строится на том, что изучает минимальные модели.
так минимальная модель как раз и вводит ограничения — что, если не сказано обратное, то всё независимо, всё атомарно, всё однородно, непрерывно и т.д.
например, когда арифметика говорит, что 1 + 1 = 2, она накладывает ограничение, что эти единицы есть независимы друг от друга, являются однородными объектами и т.д. если же мы хотим в реальности сложить 1 программиста с 1 автобусом будут требоваться более сложные модели(теории), чем арифметика. например, теория множеств и категорий
S> Вот мы вам пытаемся рассказать, что такое минимальное ООП. А вы пытаетесь то выкинуть из него неотъемлемые свойства (думая, что что-то добавляете), то засовываете в него то, без чего ООП работает.
ООП есть универсальный базис для программирования, так же как теория множеств в математике. в конечном итоге, всё сводится к этому базису: есть что-то (то, что в ООП определяется как объект), это как-то можно пощупать(то, что в ООП называется состоянием), оно как-то взаимодействуют (то, что в ООП называется сообщениями).
а дальше на этом базисе рассматриваются более слабые или более сильные модели. с введением тех или иных наборов ограничений, и получений следствий.
при чем вики говорит про тоже самое: там нет, например, никакого требования идентичности.
Object-oriented analysis and design (OOAD) is a software engineering approach that models a system as a group of interacting objects. Each object represents some entity of interest in the system being modeled, and is characterised by its class, its state (data elements), and its behavior.
The object-oriented paradigm assists the programmer to address the complexity of a problem domain by considering the problem not as a set of functions that can be performed but primarily as a set of related, interacting Objects.
Object-oriented programming (OOP) is a programming paradigm using "objects" – data structures consisting of data fields and methods together with their interactions – to design applications and computer programs.
DG>>в данном коде, с точки зрения клиента ответ приходит раньше, чем сообщение отправлено. S>С чего это вы взяли? Ничего подобного. Вы слишком вольно общаетесь с терминологией. Pong() здесь — никакой не ответ. Если хотите, я вам этот пример разберу поподробнее.
давай разбирать. в итоге, конечно, всё сведется к тому, что на данном примере накручено две ООП-модели. для той, которая считает, что Ping — это полноценное сообщение, Pong не будет ответом, а для той — которая считает, что Ping это есть половинка запроса Ping/Pong — будет ответом.
но разобраться пожалуйста — это всегда интересно.
DG>>это я к тому, что даже все ООП-языки, которые существуют, работают в рамках намного более полной ООП-модели, чем та, на которую вы ссылаетесь. S>Конечно. Реальные языки работают со значительно более сложными моделями. Но они получаются из базовой модели ООП. S>Для того, чтобы разобрать кашу в голове, нужно разделить всё, что можно разделить. Например, изучить в совершенстве базовую модель. Потом из этих мелких запчастей можно начинать строить более полезные модели.
другими словами полная цепочка получается следующей: сложная модель (например, та, которая описывает поведение хренек для которых нет полной идентичности) получена из базовой модели (в данном случае, ООП), но при этом сложная модель базовой моделью не является? (это следует из того, что ранее утверждалось, что модель в которой нет идентичности, не является ООП)
если являться не подходит, то какое здесь отношение тогда есть — между полной моделью и базовой? содержит? использует?
и чем является тогда полная модель? если она не является ООП?
DG>>в данном коде, чтобы понять в чем проблема — требуется уже вводит такое понятие как неатомарность операции отправки сообщения. S>Вы хотели сказать "неатомарность операции получения ответа на сообщение". Если что, в вашем примере есть минимум четыре момента времени (это если никаких сообщений более не происходит).
это с точки зрения модели, когда каждое вызов функции есть отдельное сообщение.
так же, как я же уже выше говорил, здесь есть и вторая модель, когда только вместе ping/pong образуют одну пару запрос/ответ.
и вторая модель более лаконично описывает поведение данного кода, но требует более сложных понятий — в данном случае, требуется понятие не атомарности запроса (уже в процессе выполнения запроса мы можем получить ответ)
Здравствуйте, vdimas, Вы писали: V>Извини, коллега, но ты как с другой вселенной. Я прекрасно понимаю, о чем ты, но не верится, что об этом можно вот так всерьез на весь интернет. Особенно когда постоянно приходится работать над быстродействием дотнетных программ. Я понятия не имею, чем вы там на работе занимаетесь, но сколько видел или участвовал в проектах... так вот, "абстрактные" программисты, не понимающие суть происходящего, для более-менее серьезных проектов банально профнепригодны. Не нужны.
У нас с вами разное понимание термина "суть".
Для вас — это то, что вы изучили в начале своей "профильной" карьеры. Поэтому все современные абстракции вы пытаетесь сначала перевести на уровень воображаемого вами процессора x86.
Для меня — это семантика, и умение свободно переходить от одного уровня абстракции к другому и обратно.
Моё понимание устройства программы делится на чётко выраженные уровни. Вот у нас уровень архитектуры приложения; вот у нас конструкции ЯП, которые эту архитектуру воплощают; вот MSIL, в который превращаются эти конструкции; вот x86, в который JIT-тится MSIL; вот микрокод, в котором работает этот x86, и особенности реальной архитектуры современных многоядерных процессоров.
Всё это — отдельно.
Благодаря этой отдельности я могу следить, на чём основаны те или иные предположения, и будут ли они оставаться справедливыми при замене того или иного уровня абстракции.
Я насмотрелся (да и сам таким был) на людей, которые сращивают все эти слои в голове в монолит. Им крайне некомфортно переходить на другие платформы, т.к. они не понимают границы применимости предположений.
Мир ведь не исчерпывается только дотнетом на x86. Есть ещё веб-программирование с его стеком AJAX-технологий; там очень многое нужно делать совсем не так, как представляется правильным в дотнетной настольной программе.
Есть, скажем, базы данных, где зазор между SQL и его физическим планом зачастую значительно сильнее, чем между C++ программой и её скомпилированным представлением.
И умение переходить от одной СУБД к другой, одновременно представляя себе последствия для производительности, невозможно получить при монолитном представлении о "сути" SQL.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, gandjustas, Вы писали:
G>>>Причем достижение первой цели не требует дополнительных знаний, а только последовательных замеров и устранения ботнеков.
V>>А если они неустранимы? Т.е. если самая затратная операция неоптимизируема никак? То уже всё или как? G>Ну так устраняй вторую самую затратную операцию, потом третью итд.
Ну так вопрос на миллион $$, если мне и так придется устранить обычно около сотни узких мест, нахрена мне по ним прыгать в произвольном порядке и рассеивать своё внимание? Внимательный скан кода дает действительно очень много и хорошо себя зарекомендовал. Не боись, работают одновременно все подходы, я лишь возражаю против того нигилизма, что вот надо только так-то и так-то... Чушь. По моему опыту, подготовка адекватных данных для любого эксперимента обходится несоизмеримо дороже программирования сценария этого эксперимента. О чем это говорит? Что надо очень хорошо понимать, какой характер данных интересует, т.е. надо оч глубоко вникать в код, прежде чем браться за всякие профайлеры и оптимизаторы, чтобы не тратить бесполезно рабочее время на подготовку данных, которые потом будут выкинуты. Я за ту же трудоемкость провожу code-review и исправляю десятки узких мест (которые и так буду исправлять), т.е. за тоже время, которое потрачу на игры с профайлером "вслепую". Еще кое-какой момент, немаловажный для самых первых итераций: зачем мне подготавливать адекватный эксперимент, сфокусированный для проверки некоторого кода, если я и так вижу, что этот код будет выкинут, как ни крути? Это же идет вразрез с основным требованием минимизации трудозатрат. Поэтому подготовка сценариев, запуск профайлеров (совсем от них отказываться никто не собирался, разумеется, просто акцент совсем не тот, что здесь толкают) и тестов на производительность подчиняется не совсем тому алгоритму, что здесь пишут "теоретики" от оптимизации. В реальности примерно так: идет обязательный code-review, отмечаются потенциально-узкие места (на все сразу на них никто не набрасывается, можно писать TODO с краткими комментариями), идет подготовка тестов самого-самого верхнего уровня. Одновременно идет зачистка самых очевидных затратных мест, но относительно дешевых в исправлении, всё это под контролем разницы показаний самых высокоуровневых тестов на производительность. По мере зачистки кода, с одновременным его более лучшим пониманием, идет подготовка все более специализированных синтетических тестов. Профайлер имеет смысл запускать, когда самые откровенные ляпы будут удалены, чтобы эти ляпы не портили нам картинку. Ни о каком "месяце вылизывания незначащего куска" не может быть и речи, это всё эротические фантазии теоретиков от оптимизаций. Основная работа при оптимизациях — это накопление тестовых сценариев, то бишь в основном данных (в плане трудоемкости) и самих синтетических и полусинтетических тестов по этим данным. А потом, когда постепенно подходим к уровню, где счет идет на микро и наносекунды (угу, у меня улучшение операции на сотню-другу наносекунд — уже нехилый профит), то какой там в опу уже профайлер! Тупо комментирую некоторые строки кода или подменяю пустышками-заглушками и смотрю на влияние на общее время низкоуровневого синтетического теста. Отдельно эти закомментированные куски тестировать на таком уровне уже не имеет смысла (заранее готовятся несколько вариантов для экспериментов), бо это уже уровень, когда стоимость вызова + конкретная проведенная оптимизация компилятором в этом месте + особенности кеширования — всё вместе создают уникальный контекст для конкретного участка кода, т.е. выдергивать код из контекста становится бессмысленным, наоборот, имеющиеся идеи в этот контекст надо подставлять. В день таких мест чистится от единиц до более десятка... Это я опять припоминаю нелепый аргумент врагов premature-optimization насчет "потратили месяц не туда". Просто, читая подобные "перлы" с трудом сдерживаюсь, чтобы не высказать, всё, что думаю о таких горе-теоретиках... Ну и, если вернуться к примеру Синклера. Ок, самое затратное место я не указал, зато указал следующие 2. Т.е. те, которые будут исправлены через пол-часа после самого затратного. Начни я работать над кодом, я бы их просто сделал в другом порядке, делов-то. Ведь никто не бросается на происзвольные куски кода (уже говорил), сначала оценивают, хотя бы устно, как часто этот код вызывается. Те, которые увидел, просматривая по диагонали, вызываются достаточно часто, т.е. должны были бы быть переделаны в любом случае, коль стояла бы задача улучшения производительности. По мере работы над примером Синклера дошел бы до оценки и того самого узкого места тоже, просто на след. итерации. Надо просто малость этим делом позаниматься, и тогда предрассудки исчезнут, в принципе ничего сложного. В рамках некоей известной платформы и известных библиотек самые узкие места известны заранее, т.е. ты их уже просто заранее знаешь, поэтому review кода нужно исключительно для того, чтобы предварительно отсеять места, где эффективность непринципиальна. Если даже где-то упустил, то профайлером потом всё-равно будет видно. Но по факту, после первых нескольких дней работы, когда накапливается достаточно тестовых сценариев и уже проведено несколько итераций оптимизации, зачищенные места почти всегда совпадают на 100% с тем, что показал бы профайлер. Вот об этом и шла речь. Над кодом Синклера никто не работал и получаса еще, чтобы делать такие далекоидущие выводы, которые ты пытаешься делать. Но если дело принципа, можно устроить "шустрик", кто выкатит более шуструю версию исходного примера. Могу пообещать не пользоваться профайлером вообще, для чистоты эксперимента.
G>А если самая затратная не устраняется, то скрой её "затратность" от пользователя.
Не скроешь, но и не надо, есть некий стандарт в отрасли. На сегодня он опустился с ~10us до ~5us на полный цикл, кроме этого надо уметь насыщать десятигигабитную сетку пакетами по 100-300 байт без всяких нагилей и уметь выгребать аналогичный поток данных на ответной стороне.
На самом деле, ты не понял цимуса. Бывает так, что профайлер покажет тебе самые затратные операции, но ты только даром потеряешь время, если не удасться их улучшить. А еще бывает часто так, что просто вызов самых затратных операций очень дорог, и стоит поменять способ вызова этих операций. В общем, "просто" показания профайлера — это слишком мало, чтобы делать хоть какие-то выводы о том, что же делать дальше. Таки разбор кода первичен, чтобы суметь соединить в голове в одно целое: характер подаваемых данных, результаты прогона профайлера и представления о том, как же работает код, т.е. почему именно так.
Здравствуйте, Sinclair, Вы писали:
V>>Второй вариант уже перестал быть императивной последовательностью вычислений или еще нет? S>Вариант — да. Язык — нет, т.к. он позволяет делать и другие "варианты".
Таки тебе эта тема интересна?
ИМХО, нет, не перестал. Ни показанный вариант, ни язык С++ не перестали быть империтивным. Сорри, но это попахивает частовстречающимся на здешних просторах ФП-закидонами, бо от функциональщиков в "запущенной стадии" часто приходится слышать противопоставления императивного и функционального программирования... хотя эти два подхода полностью ортогональны и образуют некое пространство. В общем, именно из-за приписывания иммутабельности только лишь к функциональности я эту тему не люблю. Иммутабельность — это полезная техника сама по себе, "константы" известны еще с первых языков программирования. В моем примере на С++ состояние ВСЕЙ программы изменилось после ввода и инициализации переменных. Порядок инициализации переменных в императивном программировании важен, и этот порядок задается явно. Сам термин "императив" — это приказ, инструкция, соответственно "императивное программирование" — это программирование в терминах последовательности инструкций. Если отбросить растиражированный по интернету вики-мусор, то более грамотное определение такое:
Императивное программирование — технология программирования, характеризующаяся принципом последовательного изменения состояния вычислителя пошаговым образом.
Инициализация переменных — непременное изменение состояния всего вычислителя. Без проблем можно писать императивную программу без всяких ФВП, но полностью в иммутабельном виде, реализуя циклы на рекурсиях. Противоположный полюс от императивного программирования — декларативное программирование, т.е. описание конечного результата, вместо описания способа его получения, а вовсе не функциональное программирование является противоположным полюсом, как постоянно задвигают злобные функциональщики, бо оно точно так же описывает способ вместо результата. Просто в ФП состояние вычислителя недоступно явным образом из ЯП, но оно таки есть, коль язык полный по Тьюрингу.
В общем, принципиальное отличие обсуждаемого РИ и РА — это декларативность vs явные вычисления.
(я чуть перегруппирую, соединив абзацы по одной теме)
V>>А какое нам дело до промежуточных результатов? Разве я хоть раз настаивал хоть на одной подробности реализации? Тем паче, что их много. S>Как какое? Вы же сами пишете, что результат операции зависит от результатов других операций. Это и есть промежуточные результаты, как бы по определению.
Мммм, это должно сойти за док-во, что для конкретной формулы РА порядок вычислений и прочее не важно, не так ли?
И как аргумент дал ссылку на правила раскрытия скобок в рамках этой алгебры? Оригинально. Ну вот у меня есть, допустим, некая логическая схема, и в рамках булевой алгебры я могу как угодно раскрывать скобки или наоборот, выносить составные части выражения за скобки по всем правилам, но каждый раз я буду получать уникальное решение в терминах функциональной схемы, коль дойдет до реализации. Или, программируя некую формулу в компьютере, ты, конечно, можешь раскрывать скобки "на бумаге", но каждый из вариантов будет уникальным, т.е. если входным данным придать физический смысл, то в каждом из случаев промежуточные данные будут иметь разный тип. В итоге, какой бы конкретный вид формулы ты не выбрал для программирования, для нее будет важен порядок вычисления промежуточных аргументов с т.з. их последующего применения именно в этом варианте твоей формулы, пусть даже после 100500 преобразований от предполагаемой исходной формулы.
S>Прочтите весь раздел. Если в нём что-то непонятно, задайте дополнительные вопросы.
Теория без практики мертва. (С)
Ты ведь пока не понимаешь и 50% от того, что говорю, коль приводишь как аргумент такие страницы. Специально переспросил у бывшего одногруппника, с которым поддерживаю связь — он с полуслова понял о чем речь, в отличие от. И я прекрасно вижу — почему. На голой эрудиции так далеко уехать уже не получается, надо или попытаться освоить раздел самостоятельно, или внимать коллегам.
S>>>И есть даже специальные соотношения эквивалентности, которые помогают мне это делать. V>>На уровне РА отношения эквивалентности есть только у тех операций, которые выразимы через другие... S>Повторюсь: S>http://en.wikipedia.org/wiki/Relational_algebra#Use_of_algebraic_properties_for_query_optimization
Ага, повторился.
Это таки каждый раз будет другой набор примитивных операций, для достижения того же результата. Это и есть то, о чем я говорил с самого начала, что любая решаемая задача в терминах РИ имеет в общем случае больше одного решения в терминах РА. Я так думаю, что аналогия булевой алгебры и конкретной схемы реализации некоего логического выражения должна, наконец, подтолкнуть к тому, о чем шла речь. Каждый конкретный бит сигнала-то в конкретной реализованной булевой схеме будет распространяться в общем случае через несколько вентилей, проходя их последовательно в процессе вычислений, хотя все множество поданных на вычислитель бит вычисляется при этом обычно параллельно. Никакой магии.
V>>Полностью совпадает с моими наблюдениями, и никак не коррелирует с "превосходством кластерного индекса" в твоем видении происходящего. S>Ну как это "не коррелирует". Цитирую: S>
S>2. В случае наличия кластерного индекса, остальные индексы вместо RID используют ключ кластерного индекса. Поэтому не стоит делать кластерный индекс по длинному ключу, если других индексов много
Тот абзац я скопировал ради последнего предложения:
Еще одно наблюдение – увеличение длины ключа приводит к снижению количества записей индекса, способных уместиться в пределах одной страницы, как следствие – к увеличению операций чтения-записи.
Остальное идет как контекст. Так вот, для случая кластерного индекса на странице содержится вся строка таблицы, т.е. на каждой странице будет меньше значений ключа, поэтому с т.з. быстродействия именно кластерного индекса, чем 'уже (в байтах) таблица, т.е. чем больше записей на каждой странице, тем шустрее поиск по этому ключу. Меньше потребуется просмотреть страниц в случае какого-нить двоичного поиска.
V>>Рекомендацию относительно того, как правильно готовить кластерные индексы, я дал.. ключевое только размер данных таблицы, в которой определен кластерный индекс. S>Эта рекомендация — полный бред. Размер данных таблицы не играет никакой роли. Вы не понимаете разницы между размером ключа и размером таблицы, что бы вы этим "размером" ни называли? В прошлый раз вы упоминали, что таблица для кластерного индекса должна целиком влезать в ОП — это полный бред. Не должна. Сейчас, вроде бы, подразумеваете, что "размер таблицы" — это размер одного кортежа. Тоже мимо тазика — размер ключа кластерного индекса определяется независимо от размера индексируемых кортежей.
Общий физический размер данных таблицы играет роль для принятия решения — делать уникальный ключ кластерным или нет (для неуникальных индексов кластерный работает хорошо, чуть ниже пройдусь по этой теме). Если кол-во данных в таблице относительно мало, а таблица частоиспользуема, то вполне пойдет кластерный индекс даже для случая, когда строки таблицы относительно широкие. Если вернешься назад, именно об этом с самого начала шла речь, я малость удивляюсь, почему это требуется объяснять.
V>>Насчет блобов (чтобы уже поставить точку), они именно затем и не хранятся вместе с остальными данными таблицы, чтобы обеспечить адекватную работу технологии кластерных индексов. S>Вы по-прежнему бредите. Кластерным индексам всё равно, есть в таблице блобы, и где они хранятся.
Нет, не все-равно, т.к. данные хранятся вместе с ключами. Поэтому в таблице блобы занимают всего 16 байт, а остаток значений-блобов хранится "где-то еще", причем это "где-то" можно вынести даже на отдельные диски (что я и делаю обычно).
S>У вас какое-то радикально неправильное понимание устройства кластерных индексов. Может, вам на примере объяснить? S>Вот вам таблица
S>
S>create table Person)
S> id int identity primary key,
S> passportNumber char(10) not null constraint passportNumber unique,
S> firstName varchar(max) not null,
S> lastName varchar(max) not null,
S> birthdate datetime not null,
S> picture varbinary(max),
S> // ещё поля на 4 килобайта
S>)
S>
S>Она, вроде бы, широкая. В ней даже блобы есть. Вы что, всерьёз полагаете, что что-то может помешать эффективному использованию кластерного индекса по колонке passportNumber? Нет, ничего.
Это есть объяснение работы кластерного индекса?
Кстати, подходящий пример. Если размер таблицы относительно мал, то кластерный индекс по passportNumber вполне покатит, но если же во много раз больше размеров ОП, то кластерный будет существенно сливать некластерному по тому же полю при выборе одиночных значений.
И вообще, сорри конечно, но у меня закралось предположение, что реальную производительность кластерных индексов vs некластерных ты не измерил ни разу в жизни. Более того, сама мысль, что физически размер строки таблицы "не при чем" когда речь идет об эффективности кластерного индекса (эффективности поиска по нему, надо полагать) порождает еще кое-какие подозрения, но я их оставлю на следующую итерацию. Возможно, что ты просто подзабыл кое-что...
V>>С самого начала упоминалась. Насчет памяти в силе, но объяснять облом. Лучше возьми какую-нить машинку с не очень большим объемом памяти, чтобы не заморачиваться со сверхобъемами, потсавь туда MS SQL и поэкспериментируй с кластерными индексами. Потом с некластерными. S>В ответ рекомендую открыть SQL Books Online и погрузиться в описание архитектуры кластерных индексов. Я кагбэ все эти вещи на пузе исползал крайне подробно — в том числе и базы больше размера ОП, и прочее.
Давай так, если в MS SQL 2003 и выше что-то кардинально изменилось в плане кластерных индексов, то так и быть, потрачу время на изучение и признаю неправоту (если хотя бы в двух словах обрисуешь, что именно поменялось в плане кластерных индексов). Потому как линейка от 6-ки до MS SQL 2000 была в своё время изучена настолько подробно, насколько это вообще возможно, включая местами исходники. Бо, когда у тебя в кач-ве сервака Пень III 500MHz с двумя гигами оперативки в 99-м году, то работы над эфективностью были малость не те, что сегодня, вернее вовсе не малость, а очень по-взрослому.
V>>Здесь я напомнил кое-что, хотя никто не потрудился обратить внимание, на что намекали... зато могу и впредь спрашивать? Как незамысловато протекает беседа... Ладно, давай завязывать, на что не лень здесь еще отвечу, бо ты уже потратил прилично времени, но потом не обещаю... Конкретно числа в компьютере были напоминанием обыденности ситуации неполного соответствия реализации и модели. Но это нам не мешает использовать матаппарат, до тех пор, пока мы будем находится в области ограничений реализации. S>Ключевое выделено. У вас, к примеру, понимание области ограничений весьма размыто. Это видно по непониманию, скажем, отличия трёхзначной логики от двузначной, и от последствий этого.
Тот пример, что ты привел, на "последствия" не тянет. Надо просто знать правила boolean test выражений, которые могут быть null. Действий всё-равно только два для твоего примера: включать строку в выходной результат или нет. Третьего для твоего примера не дано, хоть лопни тут, и все правила boolean test приведены в стандарте.
V>>И все это с учетом того, что вынес некластерного индекса должен давать приличный профит в плане уменьшения физического объема сканируемых данных. S>Откуда возьмётся уменьшение физического объёма сканируемых данных? Вы вообще понимаете, как работают индексы?
Отличный вопрос. Как раз подтверждает мои кое-какие подозрения. Иначе я не могу объяснить, откуда в тебе уверенность, что от размера таблицы и от относительной ширины не зависит сравнительная эффективность одного и того же индекса для случая выполнения его как кластерного или некластерного. Я не знаю, где именно ты лазил, но тестов на производительность ты точно не делал, бо там нехилую разницу легко получить, как раз на твоем примере с passportNumber, и спорить сразу станет не о чем. Еще же можно включить трейс и тупо посмотреть на кол-во сканированных страниц, наконец, для каждого из случаев. Если для некластерного у меня получалось получалось 1-2 страницы, для не самой большой таблицы, то для случае этого же индекса как кластерного — легко десяток-полтора сканированных страниц ради одного значения.
S>Да и для кластерного тоже — самое оно. Вы в качестве ключа для индекса что предполагаете выбирать?
А можно по-русски? Бо индексы бывают еще и неуникальные, т.е. могут не быть альтернативным ключом.
S>Потому что на практике каноничность не интересна. Откройте произвольное приложение, которое работает с базой данных, и поищите, сколько раз встречается select, а сколько раз distinct. Это даст вам примерное представление о доле "РА-совместимых" запросов в типичном SQL.
Сорри, но это уже вовсе безграмотно... Зачем мне distinct при выборе уникальных значений из базы в 3-й НФ? Этот distinct мы уже сократили в уме. А если неуникальные, т.е. не включающие ключи, — то они как раз выбираются для групповых операций, в т.ч. чтобы по ним специально сделать потом distinct. Ну натурально, возвращать серии повторяющихся записей из MS SQL — это верх безграмотности. Такое разве что может быть при исопльзовании базы с какой-нить системой ORM, где сервер используется как хранилище объектов и не особо обременен ни ограничениями целостности, ни прочей реляционной чепухой.
Поэтому вопрос таки в силе, показать пример реального магазина или склада какого-нить, где действительно нужно гнать на клиента последовательность повторяющихся данных без групповых операций над ними. Понимаешь, в чем фишка... Например, даже если физически уникальный ключ на клиента не идет в записи, например в данных для распечатки телефонов сотрудников, у нас априори считается, что записи сотрудников — уникальные, т.е. полная запись о сотруднике БЕЗ основного ключа является альтернативным ключом. Лишь замечу, что такое положение дел наблюдается всегда, когда мы имеем дело с суррогатным ключом, потому он и назван суррогатным, что реальный ключ тоже присутствует в характере прикладных данных.
V>>Если у вас таких "подавляющее большинство", нахрена вам вообще MS SQL? Вместо файловой системы, что ле? По опыту организация магазинов, складов, бухгалтерий и т.д. — не помню ни разу, чтобы мне нужны были данные, не попадающие в ограничения реляционной модели. S>Это у вас оттого, что вы никогда не задумывались о том, что конкретно подразумевается под "ограничениями реляционной модели".
А конкретное что-то есть, кроме общих фраз?
V>>Над никакой. Что, все СУБД реализуют стандарт SQL-92 целиком и не расширяют своими подробностями? S>Наоборот. Об этом я и говорю — есть уровень "ISO SQL" (в котором, к слову, даже индексов нет), а есть — уровень "конкретной субд".
Да просто сколько SQL-ей видел, столько раз их заново надо учить, это фактически другие языки, область пересечения диалектов ничтожна, буквально по самым простеньким запросам.
V>>Читал, давно и многократно. Давай конкретную фразу/абзац/не_важно_что, которые должны что-то такое доказать. S>
S>8.1 <predicate>
S> Function
S> Specify a condition that can be evaluated to give a truth value of
S> true, false, or unknown.
S>
Во-первых, <predicate> — это символ в нотации НФБ, описывающий синтаксис конструкции. Во-вторых, я вполне допускаю определение термина предиката в стандарте для своих нужд. Это как раз в духе моей философии об ограничении применимости артефактов. Вернее о практически отсутствующем ограничении, коль артефакты вводятся в каждую предметную область фактически искусственно.
V>>И причем тут моя голова, есть т.н. boolean test, для строки с where(predicate) если предикат is null должно приниматься какое-то решение, и решение это должно быть двоичное: включать эту строку в результат или нет. Другого не дано. S>И опять мы посмотрим в стандарт: S>
S>7.6 <where clause>
S> Function
S> Specify a table derived by the application of a <search condition>
S> to the result of the preceding <from clause>.
S> Format
S> <where clause> ::= WHERE <search condition>
S>...
S> General Rules
S> 1) The <search condition> is applied to each row of T. The result
S> of the <where clause> is a table of those rows of T for which
S> the result of the <search condition> is true.
S>
S>и далее: S>
S>8.12 <search condition>
S> Function
S> Specify a condition that has the truth value true, false, or
S> unknown, depending on the result of applying boolean operators
S> to specified conditions.
S>
Отлично, ЧТД (выделенное).
Итого, в терминах двоичной логики решение принимается так: WHERE <search condition> IS TRUE. Это и есть boolean test. Заметь, не сравнение <search condition> = TRUE, а именно тест IS TRUE.
V>>(Справедливости ради есть тонкости для right/left join, да и то не на всех базах). Конкретно в твоем примере boolen test предиката, который null, означает false. S>Нет. прочитайте стандарт. Если бы в этом случае "булевый тест" предиката означал false (а стандарт требует вовсе не этого), то NOT() от этого предиката означал бы true.
Это гребанный стыд уже...
NOT — это ключевое слово языка, который разрабатывался чтобы быть максимально близким к человеческому английскому. А что означает NOT в выражении: <expression> IS NOT NULL? Не смущает? Или здесь тоже "троичная логика"?
Таблица истинности для NOT расписана, эта операция определена в языке SQL над доменом {true, false, null}. Но! boolean test производится не над каждой операцией в выражении, а над результатом всего выражения, каким бы составным оно не было.
S>Это называется "закон исключённого третьего", и он не работает в трёхзначной логике.
Это называется boolean test, суть операция приведения значения из одного домена в другой, то бишь банальное приведение типов. Согласен, что семантика конкретно этого случая именно такая, но сам механизм отображения доменов значений гора-а-аздо более универсален. Собственно, реляционная теория этим и занимается. Твоя таблица истинности для boolean test — это и есть обычное реляционное отношение. (масло маслянное, сорри, такова специфика русской терминологии)
V>>А какая СУБД целиком поддерживает стандарт? (уже спрашивал) S>Зачем целиком? Достаточно поддерживать основные положения. Скажем, в трактовке NULL-ов у MS SQL даже есть опция SET ANSI_NULLS.
Тю, у MS SQL есть, а у MS Access уже нет. В общем, мне эта тема неинтересна, бо она по-факту малопоследовательна, глядя на мн-во реализаций SQL в различных СУБД, чтобы делать какие-то выводы.
S>>>Выдаётся результат, который не соответствует результату в РА. V>>Почему? Если значение выражения по домену {true, false, null} приводимо к boolean (например через boolean test), то проблема явно надуманна. Тем более, что есть стандарт, где это прописано... В общем, мимо. S>Что "почему"? Почему результат не соответствует результату в РА? Потому что в РА должно вернуться три кортежа, а в SQL — два. Найдите одно различие.
Ну двойка, заслуженно... Таки задач на РА мы не решали, хотя полно аналогичных тому, как ты привел. Есть домены и заданы ф-ии над ними. Задается в терминах РИ т.н. "корректно определенные формулы", которые идут как условие, необходимо составить решение в терминах РА. Вводишь отношение для преобразования одного домена в другой (таблица истинности для boolean test), добавляешь в исходную схему и расписываешь решение. Это уровень 0 задач. Оставляю как домашнее задание для собственного примера, это элементарно.
V>>Это у тебя в голове они возникают, а не в модели. Действительный пример был с повторяющимися записями в результате, но мне уже интересно, а смысл в них без агрегации? А с агрегацией — вот уже результат соответствует обсуждаемой теме. S>Я начинаю уставать ходить по кругу. Смысл — в повышении производительности. Если бы этого не было, то никто бы не стал заморачиваться поддержкой мультисетов, и в стандарт бы сразу запихали принудительную агрегацию всех промежуточных результатов.
Еще раз — не всех. Уже из 3-й НФ не факт что так просто получить повторяющиеся данные, которые заведомо не ради группировки или disctinct были получены бо (читать еще раз о физическом смысле суррогатного ключа).
В общем, если в ограничения целостности не вбили какое-то правило, то это чаще всего по соображениям эффективности, чтобы сервер не строил ненужный индекс и не делал на каждый чих лишние проверки, а не потому что такого ограничения в предметной области нет. Но вменяемое приложение не даст ввести сотрудника, у которого совпадают все поля с уже имеющейся записью, бо с прикладной т.з. нами нафик не нужен дубликат записи сотрудника, пусть даже с другим суррогатным ключом. Хоть что-то должно отличаться, даже если полное имя совпадает: адрес, возраст и т.д.
V>>Ты хотел сказать "большая часть реальных баз данных поддерживает возможность создания/оперирования данных, не подчиняющихся реляционной теории"? Ну пусть поддерживает, может кому-то и надо... Я за полтора десятка лет работы с SQL во всевозможнейших БД, начиная с самых экзотических еще с середины 90-х, эти возможности не использовал ни разу. Наверно, от недостатка образования. S>Вы эти возможности использовали постоянно. Просто в силу особенностей мышления (с обсуждения которых и начался этот тред) вы так и не осознали, где вы выходили за границы реляционной модели.
Слова, слова... Даже когда я вводил избыточность ради эффективности, я выходил лишь за рамки 3-й НФ (это водораздел совсем уж грубой избыточности), но не за рамки реляционной теории. Заметь, НФ нужны на стадии изменения данных, а на стадии выборки (коль речь об РА), если считать данные заведомо целостностными, факт соотвествия декомпозии некоей НФ вовсе не принципиален. Предлагаю помедитировать над этим.
V>>Повторюсь для невнимательных: стоит ровно противоположная задача: искать соответствия в аспектах своей частности к некоей известной модели, дабы не изобретать велосипеды. S>Чтобы искать соответствия, нужно сначала овладеть навыками анализа, т.е. разложения комплексных понятий на элементарные "запчасти". S>Потом уже можно искать соответствия между этими "запчастями" и "запчастями" из других моделей, а также заниматься "синтезом" — сборкой комплексных понятий из полученных "запчастей".
Угу, осталось сделать всего один шаг и понять, что может кардинальное отличаться терминология в разных предметных областях. Т.е. одни и те же термины в разных координатах могут означать совсем разные понятия и вполне уместен некий перевод одних терминов в другие при переходе из одной модели в другую. Судя по тому замешательству вокруг NOT, сопоставление артефактов моделей оказалось для кое-кого непосильной задачей.
V>>Поэтому искать отличия не надо, они получаются сами: это подмножество функциональности, которая выходит за рамки такого соответствия. S>Для начала нужно вообще иметь понятие о том, что есть рамки такого соответствия. Я уже почти неделю объясняю вам рамки соответствия реальных промышленных СУБД чистой реляционной модели — и несмотря на предположительное наличие у вас опыта и в теории, и на практике, дело идёт со скрипом. Даже когда я вам эти рамки сую под нос в детальных примерах и цитатах, они оказываются трудновоспринимаемыми. А вы говорите — "получаются сами".
Давай так. Ты еще ничего не обяснил. НИЧЕГО. Технические объяснения должны быть верифицируемы, а твой основной аргумент выглядит так: "вы неверно это себе представляете", что невозможно верифицировать. В техническом обсуждении вообще не принципиально, как собеседник что-то себе представляет, это его личные половые трудности. Точка опоры — это терминология и описание статики/динамики предметной области в этих терминах, больше ничего. Остальное — рассуждения в пользу бедных.
Тоже самое касательно ограничений. Я 10-й раз прошу (и знаю, почему) придумать пример, где действительно НАДО выходить за рамки реляционной теории в реальных БД. У меня такое случалось и я знаю когда я это делал — это когда БД исопльзовалась не как реляционнное хранилище. Именно это я собирался продемоснтрировать на абсолютно любом приведенном примере, иначе бы он был сведен к вполне помещающемся в рамки наработок реляционной теории. Обсуждать технические решения вообще интересно само по себе, в отличие от гаданий, насколько "монолитно" (С) что-то у кого-то в голове. Это к мозгоправу, а не сюда.
V>>А уж рассуждать о "способностях" для таких основополагающих примитивов деятельности программиста — ну это низкопробнейший обмен шпильками, что еще сказать... лучше бы опять послал почитать что-нить, иногда люди бывает подкидывают любопытные ссылки... S>Да без проблем: http://wikipedia.org S>Ещё рекомендую в гугле делать поиск с define: — это каждый раз, когда вам хочется придумать новый термин.
Ну ты видел в Вики, что одни и те же термины означают разное в разных контекстах? На то они и термины, это обслуживающий аппарат, а не целевой.
V>>То, что тебе дали дополнительный инструмент, разве означает, что первоначальный не нужен? S>Я не говорю, что он не нужен. Вы спорите сами с собой. Я говорю о том, что существует разница между реляционной моделью у Кодда, расширенной реляционной моделью, и моделью устройства реальной промышленной СУБД.
Приехали... договорились... Да какую бы я реализацию реляционной модели не взял, она будет отличаться от реляционной модели хотя бы потому, что реляционная модель никак не ограничивает свою реализацию. Не понимаешь? Изначально подробностями реализации пренебрегли. Есть, конечно, кое-какие практические наработки и исследования стоимостей операций при разных способах хранения данных, но это сугубо инженерные исследования в конкретных, с т.з. инженерии, условиях, никак не связанных, разумеется, с теорией.
Вопрос на мильон $$, почему в рамках теории реляционных СУБД постоянно упоминается "несогласованное обновление", "ошибки целостности" и т.д. Ведь, с т.з. РА, например, такое невозможно?
ИМХО, ты классически ставишь телегу впереди лошади. Не РА является определяющим в отношениях теории и практики, а наоборот, когда данные УДАЛОСЬ привести в рамки требований РА, можно начинать применять сей аппарат. Это общий алгоритм в любом случае, когда ты хочешь использовать какой-либо матаппарат для своих нужд, не только для реляционных СУБД.
S>Да что тут ломать-то? Независимо от НФ, любая проекция, не включающая в себя primary key, сразу даст вам потенциальные повторы.
Ну, что-то вроде подобного я и ожидал. Поздравляю. Какая именно проекций и зачем она без ключа?
Повторюсь, если ключ был суррогатный, то "потенциальность" повторов очень под вопросом. А если не суррогатный, то я хочу увидеть задачу целиком и убедиться что да, повторы были оправданы. Мне нужен верифицируемый пример.
S>Дистинкт по этим данным конечно же снизит производительность — потому что это group by со всеми вытекающими. В частности, нельзя использовать стриминг и резко возрастает потребность в буферах для промежуточных результатов. При низком коэффициенте повторяемости гораздо эффективнее отложить этот group by до момента, когда он реально нужен.
Господя. MS SQL способен выдавать данные быстрее, даже с учетом всех join и т.д. на современных серваках, чем дотнетный парсер на стороне клиента способен парсить приходящие данные, а потом еще делать ORM. О чем ты тут пытаешься фантазировать?.. Что и как ты меряешь, не поделишься техникой? Тем паче, что возврат более нескольких сотен (грубо) записей из MS SQL всегда просит к себе некоторого внимания, на предмет "а зачем так?".
V>>Ну вот отделил ты операцию "фактор" от остальной РА, например. Поделишься ощущениями? S>Прекрасные ощущения, а что?
Ну ты же настаивал на отделении "мух от котлет", мне интересно, что ты под этим понимаешь, что есть у тебя и нет у оппонента. Только лишь "прекрасные ощущения"?
V>>Это отрицание возможности применения наработок и опыта по РА для реализации некластерных индексов, например. S>Какие именно наработки РА вы хотите применить для реализации некластерных индексов?
Уже показывал декомпозицию с вводом системного суррогатного ключа, некоего адреса строки, обеспечивающего O(1) для доступа. Хотя, указанная факторизация лежит вне РА (хоть и совсем рядом), все операции над декомпозицией можно проводить, используя аппарат РА. Исключения составляют неуникальные индексы, которые являются спорной техникой сами по себе, если не являются кластерными при этом. Это я к тому, что делать кластерным внешний ключ бывает намного полезней, чем основной, в плане эффективности. Именно потому, что по основному ключу достается единичная запись, а по внешнему мн-во, поэтому порядок хранения записей начинает играть роль.
V>>Блин, сам же даешь неплохие аналогии, и сам же против них споришь... В 99% случаев ньютоновской за глаза в обычной жизни. А если по какой-то частности не хватает ньютоновской, то берут релятивистскую, но только по этой частности. Так же проще. S>Не "по какой-то частности", а "для какой-то задачи". И если в задаче нужна релятивистская механика, то будь любезен всю её решать в ней. А не так, что, скажем, скорости ты считаешь релятивистски, а время принимаешь ньютоновским.
Это внутри одной формулы так. А если задача разбита на буквально тысячи слабосвязанных аспектов, для каждый аспект я буду решать максимально удобно. Коль пойдет ньютоновская в рамках заданной погрешности на множестве операций — значит будет ньютоновская.
S>Да у вас куда ни ткни — везде непонимание и заблуждения.
деление на декларивный и императивный код появилось на заре становления программирования при решении задачи: может ли меняться код исполнения при той или иной записи программы? и в какой степени?
пока не было оптимизирующих компиляторов деление было более-менее четкое:
пролог, sql — декларативные: исполнитель делает что хочет;
а асм, алгол, форт, паскаль, си — императивные: исполнитель делает то, что записано в коде, в том порядке в котором записано.
как появились оптимизирующие компиляторы — императивные языки перестали быть четко императивными, в них появилась декларативность: исполнитель в большинстве случаев стал выполнять другой код и в другом порядке, чем записано.
дело дошло даже до того, что маш. код перестал быть чисто императивным: современный процессор его выполняет в другом порядке, и другим способом чем записано
и наоборот, по мере стандартизации де факто реляционных баз — от большинства простого sql-кода стало ожидаться, как именно он будет исполняться (в каком порядке какие выборки будут делаться, какие индексы будут использоваться и т.д.)
и sql перестал был четко декларативным: от конкретной реализации СУБД (тем более конкретной версии) ожидается, что sql-запрос будет выполняться строго заданным способом, и никак иначе.
соответственно, сейчас дискуссия о том является ли конкретная запись декларативной или императивной — это дискуссия ни о чем:
сейчас многое зависит от исполнителя (мощности его анализатора кода и возможностей его выполнения) — и без фиксирования исполнителя нельзя утверждать — этот код декларативный или императивный. а если зафиксирован исполнитель, то прежде чем говорить чего больше: декларативности или императивности необходимо сначала зафиксировать метрику — в каких единицах и каким способом измеряется декларативность или императивность.
при этом можно говорить, что такая запись более декларативная/менее императивная без явной фиксации исполнителя, если при этом измеряется какую степень свободы для исполнения дает та или иная запись; или если сравнивается мощность анализатора исполнителя, чтобы исполнитель мог получить ту или иную свободу исполнения, для той или иной записи кода.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>нет, я поражаюсь, как легко можно изменить терминологию, устоявшуюся десятилетиями.
I>Э нет, тут как раз наконец-то в стандарте прописали терминологию, устоявшуюся десятилетиями, а именно термин reference variable.
В стандарте такой термин не упоминается.
A reference variable is an alias, that is, another name for an already existing variable. Once a reference is initialized with a variable, either the variable name or the reference name may be used to refer to the variable.
C++ references allow you to create a second name for the a variable that you can use to read or modify the original data stored in that variable.
...
When a reference is created, you must tell it which variable it will become an alias for.
As soon as we declare a variable, the amount of memory needed is assigned for it at a specific location in memory (its memory address). We generally do not actively decide the exact location of the variable within the panel of cells that we have imagined the memory to be — Fortunately, that is a task automatically performed by the operating system during runtime. However, in some cases we may be interested in knowing the address where our variable is being stored during runtime in order to operate with relative positions to it.
The address that locates a variable within memory is what we call a reference to that variable. This reference to a variable can be obtained by preceding the identifier of a variable with an ampersand sign (&), known as reference operator, and which can be literally translated as "address of".
DG>>при этом ты утверждаешь, что оператор == для value-типов в .net сравнивает побитово? S>хм, для predefined — да.
нет, же. конечно.
вот тебе два контрпримера. в одном случае битовое представление одинаковое, но == возвращает false.
в другом случае — обратное. битовое представление различное, но сравнение одинаковое.
DG>>>в целом, вроде согласен. DG>>>смущает только середина. что здесь такое subtype? является ли, например, int субтипом double? вообще? и в конкретных языках программирования? S>>так ты сходи по ссылочке из вики.
DG>NullObject как раз под это определение подходит, а NullObject в зависимости от договоренностей и возможностей языка может реализовываться и через null
Т.е. ты решил null сделать подтипом объетка, что бы вписаться в формулировку?
S>>Зачем выдумывать язык для NullObject?
DG>потому что это отдельный subtype, требующий отдельного описания.
А язык-то зачем выдумывать? NullObject можно вписать много куда.
S>>Этот код не полиморфен. null здесь не абстрактный null.
DG>с точки зрения выделения subtype — это не требуется. DG>также не требуется, что subtype (и type) соответствовали типам из ЯП на котором реализуется программа.
У тебя и с типами такая же каша?
S>> Это значение типа ссылка на Point. Здесь в цикле ты работаешь с одним единственным типом — Point. Потому по определению никакого полиморфизма не будет. Если, конечно твой null-объект не окажется унаследованным от Point...
DG>когда я пытаюсь сформировать видение твоего мировозрения, то у меня появляется чувство диссонанса. DG>1. с одной стороны, ты вроде понимаешь, что абстрактные (как концепции) type, subtype, object, полиморфизм и т.д. существуют в коде в независимости от того, как в ЯП реализованы их конкретные аналоги, и что при этом отношения между абстрактными и конкретными аналогами не 1 к 1. DG>2. с другой стороны, утверждения ты часто строишь по схеме — в моем любимом языке конкретная реализация подразумевает то и то, из этого следует, что в моем любимом языке тоже самое следует и для абстрактных type, subtype, object и т.д.
А я что-то говорил про свой любимый язык?
Понимаешь, сколько не думай о системе типов дотнета как о системе типов хаскеля, она ею не станет. Потому, все решения, которые можно записать в дотнете, объяснимы в терминах системы типов дотнета. Даже если что-то придется эмулировать, то это что-то имеет объяснение в терминах типов дотнета. И что бы объяснить это решение или что-то доказать, не нужно выдумывать новые определения, которые чреваты косяками типа идентичности всевозможных строк.
S>>сделать глубокую копию списка поинтов, инвертировать поинты в нем, потом перенести изменения на поинты исходного списка.
S>> потом перенести изменения на поинты исходного списка
DG>как вот это будет делаться за O(n), и какой алгоритм будет использоваться для понимания, какой immutable-объект из результата какому mutable-объекту соответствует? в частности для тех же point-ов
Тривиально
var list1 = list.Select(p => new Point(p.x, p,y)).ToList();
for (int i = 0; i < list.Count; i++)
{
var p = list1[i];
p.Inverse();
list[i].x = p.x;
list[i].y = p.y;
}
S>>Ты надеешься что суперкомпиляция сможет нарисовать код, который с нулевыми затратами будет преобразовывать мутабельные поинты в иммутабельные и обратно после инвертирования иммутабельных?
DG>суперкомпиляция, как минимум, на основе immutable-кода может построить его inplace-версию кода поверх mutable-объектов, и такой код имеет нулевые затраты.
Если не в лом, покажи мне код после суперкомпиляции. Хотя бы то, как мог бы выглядеть его аналог с мутабл объектами.
DG>>>вернемся к математике: DG>>>поверх булевой логике можно построить поле 1 со следующими правилами(допущениями): DG>>>операция + поля: xor DG>>>операция * поля: and DG>>>нулевой элемент поля: false DG>>>единичный элемент поля: true DG>>>поверх поля 1 можно построить поле 2 со следующими допущениями: DG>>>операция + поля: and DG>>>операция * поля: or DG>>>нулевой элемент поля: единичный элемент поля 1 DG>>>единичный элемент поля: нулевой элемент поля 1
S>>С математикой ты не дружишь. В "поле 2" нет нейтрального элемента для (+).
DG>не тормози.
Да, с этим я тормознул.
А покажи мне существование обратного элемента для false относительно сложения (and) для поля 2. Напомню, что сложение с обратным элементом должно дать ноль, т.е. true.
S>А покажи мне существование обратного элемента для false относительно сложения (and) для поля 2. Напомню, что сложение с обратным элементом должно дать ноль, т.е. true.
на самом деле, я действительно не прав. извини.
or и and не образуют группу, хотя я почему-то считал обратное.
зы
значит в построении 2 придется брать в качестве операции +: операцию эквивалентности
Здравствуйте, DarkGray, Вы писали:
DG>и разделение одной функции на несколько вариантов делается как раз под такую технику. и разделение имеет смысл, если удалось выделить более часто используемую и более простую реализацию исходной функции.
Ок, я понял вашу идею. К сожалению, она не поможет вам разобраться с математическими аспектами декларативности и императивности. Вы опять закапываетесь в подробности и устраиваете кашу вместо того, чтобы расставить всё по своим местам.
Итак, библиотека от реальной программы не отличается ничем. Ну, то есть если мы не трогаем "одноразовые" программы.
Одноразовые программы — это те, у которых нет входных данных. Можно написать программу по проверке, является ли число 913287463628254622746920 простым. Но второй раз запускать эту программу смысла нет — мы можем просто взять её результат из журнала предыдущего запуска.
Такие программы перестали интересовать программистов лет наверное 60 назад. Сейчас интересно иметь программы, которые способны работать для разных входных данных.
"Библиотека" — это всего лишь программа, или "набор программ", которые имеют шансы повторно использоваться в разных применениях.
Вот я могу иметь программу для вычисления синуса какого-то числа. Это программа? Безусловно, программа. Имеет ли смысл включать "программу по расчёту синуса" в библиотеку? Безусловно, имеет.
То, что у кого-то расширение .dll, а у кого-то — .exe, нерелевантно в данной дискуссии.
Скажем, почти весь юникс состоит из таких "программ", которые вроде бы программы, но сами по себе почти что бесполезны, т.е. являются "строительными кирпичами" для других программ.
То есть у нас нет формального критерия, по которому мы могли бы отличать одни "многоразовые программы" от других "многоразовых программ". (Если вам вдруг захочется ввести метрику типа "степень библиотечности" — то желаю удачи. Лично я не вижу ни одного способа сделать это, который бы смог выдержать хотя бы лёгкую критику. )
Этот вывод, как мы видим, опровергает основу для ваших рассуждений про некие возможности для "реального" кода:
как только появляется реальный код для которого выполняется однозначность, по нему всегда можно восстановить спецификацию результата
Ведь у нас нет никакого "реального кода" и "нереального кода".
Для того, чтобы мы могли делать какие-то заключения о том, что у нас является "спецификацией результата", а что является "подробностью реализации", нам нужно явно обозначить результат. Императивная программа отличается от декларативной именно тем, что в ней нет "спецификации результата", а есть спецификация "действий". "Действия" в программировании — это "изменения состояния". Нет изменения состояния — нет действий, нет действий — нет императива.
Когда вы для некоторой декларативной программы формируете некоторую императивную программу, то вы не получаете "ту же самую" программу. Я понимаю, что вам хочется так думать, но вы не в первый раз повторяете ошибку, путая эквивалентность с идентичностью. Вы получаете другую программу. Об эквивалентности этих программ можно рассуждать только после того, как мы определили критерии сравнения. Я вам уже показал пример того, как сильно можно промахнуться, если слишком поверхностно определять критерии сравнения.
Даже если задать критерии эквивалентности "на основе спецификации результата" удовлетворительным образом — т.е. так, чтобы не было очевидного способа подсунуть неработоспособную программу под эти критерии, — то всё равно окажется так, что внутри одного класса эквивалентности находятся существенно разные программы.
К примеру, и пузырёк, и quicksort получают один и тот же результат. Но редкий программист рискнёт назвать их "одной и той же" программой. То же самое касается наивного преобразования Фурье и быстрого преобразования Фурье.
Это всё же очень разные программы. И пока что нет никакого удовлетворительного способа автоматически получать одно из другого. И не важно, идёт ли речь о переходе от императивной программы к декларативной или наоборот.
Ну, то есть я слышал о том, что вроде как есть декларативные языки, которые по предикату "отсортированности последовательности" ухитряются рожать код cортировки, и вроде бы даже этот код работает за NlogN. Но я практически полностью уверен, что даже медленное преобразование Фурье получить по его декларативному описанию пока что без помощи программиста не получится.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, igna, Вы писали:
I>Вот хрен, 123 здесь integer literal (значением которого инициализируется объект именуемый i).
I>На неважно, главно, что ты увидел определение неизменяемого объекта здесь:
I>
Здравствуйте, igna, Вы писали:
L>>Имя никогда не означает "само себя".
I>Ну вот же в твоей цитате:
I>
L>>Палец указывающий на Луну, не есть Луна
Для того, чтобы обозначить "Палец указывающий на Луну" одного его недостаточно, нужен другой палец, указываюший на "Палец указывающий на Луну". Или не палец.
Здравствуйте, Lloyd, Вы писали:
L>Для того, чтобы обозначить "Палец указывающий на Луну" одного его недостаточно, нужен другой палец, указываюший на "Палец указывающий на Луну". Или не палец.
Да, этот форум стал просто фиеричен. Такие флэймы с такими аллегориями, по такому, казалось бы, прозаичному вопросу.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, grosborn, Вы писали:
G>Поскольку внутреннее состояние всегда изменяет поведение...
Вообще-то частью внутреннего состояния может быть кэш, влияющий не скорость, но не на результат; так что в зависимости от того, что понимать под поведением, твое утверждение может быть неверно. Если скорость в определении того, что считать поведением не учавствует, твое утверждение неверно.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>По-моему ты это сам придумал. Для меня, например, "Вася" и "слесарь Вася", обозначают не одно и то же.
I>Ну-ка, ну-ка. Представь себе, что ты сидишь со слесарем Васей за одним столом; в этом контексте и при отсутствии в нем других Вась, "Вася" и "слесарь Вася" именно одно и то же для тебя обозначают.
Кашпировский, что ли?
А теперь смотри сюда, Анатолий Михайлович:
int const i = 123;
Так ли это, можно ли назвать i здесь immutable?
В этом контексте Вась (immutable) как минимум двое. Один — значение 123, второй — переменная. Мне было непонятно, о чем ты спрашиваешь. Раз ты не написал, что конкретно ты подразумеваешь под "i", я раставил акценты (и не только я).
Но ты продолжал гнуть
К объекту то есть (по крайней мере в C или C++, на котором пример, i является объектом)
Теперь представь себе, что ты сидишь за одним столом с двумя Васями, один из которых слесарь, а другой — кот. И ты утверждаешь что кот является слесарем Васей.
I>>Так ли это, можно ли назвать i здесь immutable?
DG>переменную, в общем случае, можно считать объектом, и при этом условии в данном коде i является immutable object.
Мой поинт в том, что в общем случае переменную нельзя считать объектом, ввиду различного времени жизни объекта и переменной, а так же того, что на протяжении жизни переменная может быть отождествлена с различными объектами, в том числе обладающими различным поведением.
И особенно переменную от объекта следует отличать в аспекте возможности изменения.
Здравствуйте, samius, Вы писали:
S>Мой поинт в том, что в общем случае переменную нельзя считать объектом, ввиду различного времени жизни объекта и переменной, а так же того, что на протяжении жизни переменная может быть отождествлена с различными объектами, в том числе обладающими различным поведением. S>И особенно переменную от объекта следует отличать в аспекте возможности изменения.
В частном случае — можно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>И особенно переменную от объекта следует отличать в аспекте возможности изменения.
отличать необходимо то, что отличается.
а переменная является частным случаем объекта, и обладает двумя методами(сообщениями) getValue/setValue, и соответственно константная переменная (или readonly-переменная) является immutable-объектом, обладающим одним методом getValue
Здравствуйте, DarkGray, Вы писали:
S>>неожиданный поворот. Ну что же, тогда я настаиваю что следует отличать "объект переменная" от "объекта значения",
DG>согласен.
S>> т.к. они в общем случае обладают различными ответственностями и наборами сообщений.
DG>их можно считать полиморфными друг другу, тогда они будут обладать одним набором сообщений, но вот поведение — да, будет отличаться.
"Полиморфными друг другу" — это непонятно в отношении объекта и переменной.
Один набор сообщений — это спорно. объект-значение не имеет метода setValue: 1.setValue(2) — что-то нелепое.
S>>А если поковыряться, то окажется, что у переменной нет метода getValue, а вместо этого есть обязанность обеспечивать доставку сообщений объекту-значению.
DG>можно рассматривать и такую модель, но такая модель требует больше информации для описания (более сложная)
Может тогда вообще не стоит делать объект из переменной? Ради чего, собественно?
S>> setValue тоже может не быть. Так, например, в C++ вместо setValue переменной работают конструкторы копирования/операторы присваивания значений. И работают они не с переменными, а со значениями.
DG>в C++ есть и setValue, и конструктор копирования, одно другому не мешает. DG>и присвоение выглядит как: DG>
Если поле объекта-переменной тоже считать объектом с методом setValue, то код выше представляет собой бесконечную рекурсию. Оно нам надо?
S>>В C# — да, можно считать что у переменной есть setValue. Но в C# нет возможности объявить неизменяемую переменную.
DG>есть такое. но при этом никто не мешает считать переменную, которая не меняется, как неизменяемую переменную.
Можно, но тогда придется считать неизменяемыми объекты, которые никто не менял по факту, а не по отсутствию возможности его изменения.
Здравствуйте, DarkGray, Вы писали:
S>>Один набор сообщений — это спорно. объект-значение не имеет метода setValue: 1.setValue(2) — что-то нелепое.
DG>такое сообщение есть, и оно даже отрабатывается, выдавая ошибку. DG>можешь сам попробовать написать 1 = 2 в любом языке, в котором '=' означает присвоение
В любом компилируемом языке до сообщения не доходит, т.к. ошибка времени компиляции, а не выполнения.
S>>Если поле объекта-переменной тоже считать объектом с методом setValue, то код выше представляет собой бесконечную рекурсию. Оно нам надо?
DG>не надо так считать. те же самые обозначения лишь используются для того, чтобы не вводить новых сущностей.
Т.е. поле (которое на самом деле instance variable) объектом не считается, в отличии от local variable?
DG>также ряд понятий (как, например, присваивание) являются неопределяемыми, и можно лишь показать свойства, которыми они обладают.
Полагаю что в конкретных языках присваивание определяемо. DG>что в данном случае и показывается. показывается, что работа с переменными не отличима от работы с объектами. DG>"а если что-то выглядит как кошка, то оно и является кошкой" (c).
Но отличия есть. См. 1 = 2, &(a + 1), ...
S>>Можно, но тогда придется считать неизменяемыми объекты, которые никто не менял по факту, а не по отсутствию возможности его изменения.
DG>фраза построена так, что мне в ней видится намек на то, что это приведет к чему-то плохому. DG>это так и есть? но тогда, в чем опасность? или это мне лишь чудится.
Опасность в том, что мы отойдем от определения неизменяемого объекта и начнем фантазировать. Придется вводить понятие контекста неизменяемости, т.к. объект не сможет быть неизменяемым в классическом понимании, но раз мы захотим называть его изменяемым, то нужно будет оговариваться, с какого момента он неизменяем, в каком контексте, на протяжении каких вычислений. Неизменяемость будет не атрибутом типа объекта, а атрибутом конкретного экземпляра в конкретных условиях.
Мы даже на этапе анализа кода не сможем сказать, изменяем ли объект или нет:
if (someCondition)
b.UpdateState();
DG> тот же оптимизирующий компилятор, или там resharper — так и считает, когда, например, проводит оптимизации или refactoring, и этом им обеспечивает больше возможностей.
Но для разработчика на стадии написания программы фактическая неизменяемость изменяемых объектов — слишком эфимерное понятие. Особенно, если оно никак не декларируется и не проверяется компилятором.
Здравствуйте, VladD2, Вы писали:
VD>Да, этот форум стал просто фиеричен. Такие флэймы с такими аллегориями, по такому, казалось бы, прозаичному вопросу.
Только что хотел написать ровно такой же пост. Жесть какая-то, при том, что вполне уважаемые мною форумчане на полном серьезе ломают тут копья.
Люди, одумайтесь, вопрос выеденного яйца не стоит, просто некоторые готовы любую мысль довести до абсурда и и посчитать это философией.
S>По определению. Для того, чтобы что-то можно было трактовать как объект ООП, оно должно обладать идентичностью. Причём всегда, а не так, что с утра идентичность была, а в обед её уже нету. Потому, что это означает, что построенные на идентичности решения с утра работают, а после обеда — нет.
так вроде тогда правильный ответ, что надо строить решения на чем-то другом (например, на частичной идентичности), и жизнь сразу наладится. разве нет?
S>С чего вдруг? Мы не говорили о достаточности. Мы говорили только о необходимости.
речь идет именно о достаточности. потому что, например, модель вида "здесь используем идентичность, здесь — не используем, а здесь используем частичную идентичность;
здесь используем булеву логику, а здесь используем другую логику" включает в себя модель "мы только работаем с объектами с постоянной идентичностью и только с булевой логикой".
DG>>возьмем, как пример анонимный чат — там всё еще как-то понятно с точки зрения идентичности сообщений, но с идентичностью субъектов, которые эти сообщения постят — всё очень и очень непросто. но ведь необходимо и эту задачу уметь решать. S>Не вижу формулировки проблемы. Опять же, нужно понимать, что мы говорим не о реальном мире, а о программировании. Нас вопросы идентичности реальных субъектов вообще никак не интересуют.
вот этот постулат не понятен.
программирование мы используем для того, чтобы решать какие-то задачи в реальном мире, а не само по себе в вакууме.
и соответственно, если мы даже в реальном мире не можем разобраться на многих задачах с идентичностью, а программист утверждает, что он готов решать только задачи, где есть строгая идентичность, то получается — а нафиг нам такое программирование и такой программист, который нам ничем помочь не может?
DG>>или, например, возьмем машину — например, до какой степени машина идентична сама с собой по времени? по какому свойству определяется идентичность? по цвету, по номеру, по царапине на крыле? S>И какое отношение это имеет к программированию?
потому что программирование это перевод реальности в модель. соответственно, если в реальности нет строгой идентичности между объектами, то откуда она появится в модели?
DG>>или есть даже брать чисто программисткие заморочки — объект хранящийся в базе, он же на сервере, а потом на клиенте — это один и тот же объект? или это три разных? S>Это зависит от выбранной модели. Разве это не очевидно?
можем ли мы одновременно использовать две модели: одна которая утверждает что это идентичные объекты, а другая — что это разные?
или другими словами: можем ли мы использовать модель — которая в одной части утверждений считает, что это идентичные объекты, а в другой части утверждений считает, что это неидентичные объекты?
S>А, не ну если мы будем баловаться с небезопасными фичами C++, то можно сразу же забить на любые рассуждения о свойствах С++ программ.
так я тебе сразу говорил, что про эквивалентность можно лишь говорить на каком-то наборе операций, и что стоит это сразу оговаривать. В данном случае, ты рассматриваешь эквивалентность лишь на наборе безопасных операций.
но ты не стал это слушать, а начал бегать с шашкой и кричать: что в моем любимом языке можно утверждать, что переменная и ссылка — эквивалентны всегда безотносительно набора операций.
когда же я тебе показал, что это не так, твоя реакция свелась к "я так не играю".
соответственно, я также утверждаю, что переменные и объекты эквиваленты между собой на "безопасном"-наборе: получить/записать значение
Здравствуйте, DarkGray, Вы писали:
DG>если послушать тебя с синклером, то выяснится, что и nullable-чисел не должно существовать. из-за того, что математика требует, чтобы числа существовали всегда.
Не имею понятия, что такое nullable-число
Здравствуйте, samius, Вы писали:
S>>>Хорошо, пусть будет объект, инициализированный значением этого литерала. Но i — это не объект. Это идентификатор.
V>>Для случая оперирования по значению, это одно и то же. S>Возражаю. Идентификатор один, значения разные. Уже это дает повот делать различия.
Нет никакого идентификатора в рантайм, это условное обозначение времени компиляции, чтобы тебе было легче отличать один адрес от другого. Но сама сущность "переменная" никуда не девается в рантайм, в отличие от идентификатора. И что ты подразумеваешь под "значения разные"? Конечно, с т.з. ООП, объект может иметь разные состояния, поясни, где ты видишь противоречие? Неужели только из-за того факта, что можно целиком заменить состояние объекта? Но ведь можно так же не целиком даже для объектов, хранящихся по-значению на стеке (модифицируя только часть полей или вызывая методы, модицифицирующие только часть полей). И точно так же можно целиком изменить состояние объекта, хранящегося на куче, т.е. по неизвестному адресу времени компиляции, поэтому для доступа к которому мы используем переменные ссылочного типа. Абсолютно одинаковые сценарии изменения состояния доступны в обоих случаях.
Что касается переменных примитивных типов, то стоит таки обратиться к определению ООП, данное Алланом Кеем, но целиком, а не только к первому предложению. Конечно, он вводит понятие "примитивных" типов, ибо где-то должна быть точка отсчетов для построения более сложных композиций из простых. Но экземплярам этих "примитивных" типов никто не мешает быть полноценными объектами. Разница лишь в том, составные это типы или нет, т.е. какова размерность пространства состояний объекта. Согласись, это отличие не означает неприменимости парадигмы ООП к таким примитивным типам. Например, любой объект, имеющий всего одно не ссылочное поле примитивного типа, хоть и является строго говоря составным, но демонстрирует все характеристики точно такого же примитивного типа в плане его пространства состояний. Скажу больше, такие объекты обычно делают для ограничения исходного пространства состояний примитивного типа, т.е. протягивая некую зависимость тип-область_значений в систему типов программы.
Ну и, возвращаясь к идентификатору. Есть такое понятие identity, это не есть идентификатор. В рамках одной программы identity объекта есть его адрес (даже если предвидеть возражение насчет операций GC по передвижкам объектов, то ведь он подменяет так же все ссылки на него, в т.ч. ref ссылки на внутренние поля объектов, поэтому такая процедура прозрачна для программиста). А в распределенных средах как identity выступает обычно некий токен из байт или подмножества байт (символов), который опять же нужен для перевода на каждой стороне этого токена в адрес объекта.
I>>>>А употребленное тобой "имя переменной" это в терминах чего было? S>>>Хорошо, пусть будет "идентификатор".
V>>Имя переменной тоже неплохо, в чем проблема? По определению, переменная в ЯП — это именованный адрес. S>ЯП — это другой уровень. Я говорил в терминах ООП.
ООП полностью зиждется на процедурном подходе и использует его аппарат для своей реализации. Семантику сущности "переменной" он не изменяет ни разу. Да и какая разница, хранится ли объект на куче, на стеке или как поле другого объекта (т.е. непосредственно по значению). Расположение объекта в куче не дает этому сценарию никаких отличий в плане парадигмы ООП, в сравнении с остальными способами расположения объектов. Разница есть, например, для GC в управляемых средах, так же как есть ограничения (например, невозможно получить и сохранить safe-ссылку на поле внутри объекта), но это никакого отношения к самому ООП не имеет.
Здравствуйте, DarkGray, Вы писали:
DG>например, в ООП не вводится понятия времени.
В ООП время вводится неявно — как последовательность состояний и сообщений.
Думать, что его нет, не надо.
Если бы в ООП совсем не было времени, то невозможно было бы определить, какое из сообщений приходит раньше других. И понятие состояния не имело бы смысла.
Чего в ООП-шном времени нет "из коробки", так это понятие длительности.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vdimas, Вы писали:
L>>Переменная — понятие конкретного языка программирования, оно служит для идентификации какого-то значения, используемого в прграмме. L>>Поэтому в каком-то смысле переменная является "ссылкой".
L>>
V>Эээ... че-то я теряюсь, на всяк случай тут приводил разбор способов адресации: http://www.rsdn.ru/forum/philosophy/4505309.1.aspx
Здравствуйте, Sinclair, Вы писали:
S>Тем не менее, обсуждать семантику MSIL в терминах некоторой конкретной машинной реализации мне кажется несколько поспешным. И MSIL никак не слишком высокоуровневый. Его уровень — в самый раз. Вся семантика дотнета определена в терминах MSIL. Семантика шарпа определена в ещё более высокоуровневой форме. Там то, что выглядит стековой переменной, запросто может в MSIL превратиться в поле
объекта.
Замыкания меняют семантику переменных, время ее жизни перестает быть ограниченной scope, в котором она определена, поэтому не вижу противоречий. Таки время жизни переменной все еще очень важное понятие, даже в шарпе.
V>>Можно, для явного размещения полей, для маршаллинга даже без явного размещения полей. Узнать можно смещение любого поля уже загруженного типа. В любой легальной дотнет-программе. S>И тем не менее, смещение любого поля в обращении к полю не используется. Если не верите — откройте рефлектором любую дотнет-программу и посмотрите, как устроена команда ldfld.
Обращение по токену относитльно экземпляра. Большая разница? что должен озанчать токен, чтобы всё это работало правильно У ЛЮБОГО экземпляра этого типа? И чем тебе токен не адрес, в случае даже ассоциативной адресации, как в объектах языка JS, например?
V>>Ты имел ввиду в шарпе не используется? А в каком высокоуровневом ЯП напрямую фрейм стека доступен? И почему относительно других языков никто не возражает, что доступ к локальным переменным относительный, относительно текущего фрейма стека? S>Относительно каких языков? Относительно ассемблера — не возражает.
Мне понятие "локальных переменных" преподавали когда-то на примере Паскаля. Не вижу принципиальных отличий от шарпа. Без сущности "стек", "стековые переменные", "фреймы стека" невозможно описать семантику дотнетной байт-машины.
S>Относительно даже С уже вопрос о фрейме стека является чисто умозрительным. Никто не мешает оптимизатору разместить локальные переменные, скажем, в регистрах. Именно потому, что доступ к локальным переменным формулируется по именам локальных переменных, безо всяких ссылок на фрейм стека.
Ну мало ли что есть в современных оптимизаторах. Мы же оперируем семантикой, т.е. программа должна работать даже на таких процессорах, например, все регистры которого индексные, и предполагают исключительно косвенную адресацию, хоть в терминах программы мы исопльзуем непосредственную или прямую. Семантика меняться не должна. Для этого должна быть некая эталонная модель, к которой мы привяжем семантику программы, закрыв гляза на подробности реализации модели на разных платформах. Относительно байт-машины дотнета сюда можно вставлять предыдущий абзац.
V>>Понятие фрейма стека в ходит в описание работы дотнетной байт-машины, так что для нее всё это справедливо. S>Рекомендую (в рамках само-ликбеза) всё же ознакомиться с описанием работы дотнетной байт-машины. Потому что managed stack устроен совершенно не так, как вы пытаетесь это представить, и адреса его ячеек нигде в описании не фигурируют.
V>>Ну и к тому же в MSIL используется и то и другое, если речь именно о дотнете, а не о шарпе. Чем тебе индекс стековой переменной не адрес? S>Тем, что это никакой не адрес.
По определению самого термина "адреса", адрес — это порядковый номер ячейки. Так что, мое вам с кисточкой в плане само-ликбеза.
Здравствуйте, vdimas, Вы писали:
L>>Ничего личного, но вы путаете понятия времени исполнения и понятия языка программирования.
V>Если бы способы адресации были не важны, их бы не проходили на первых курсах профильной специальности. Надо понимать что и как работает, чтобы адекватно использовать любую технологию, не делая заведомо неверных допущений (суть проявляя безалаберность и безответственность). Таки запас по эффективности и ресурсам пока еще не тысячекратный, чтобы позволить себе это.
Здравствуйте, vdimas, Вы писали:
V>Замыкания меняют семантику переменных, время ее жизни перестает быть ограниченной scope, в котором она определена, поэтому не вижу противоречий. Таки время жизни переменной все еще очень важное понятие, даже в шарпе.
Это правда. Но
V>Обращение по токену относитльно экземпляра. Большая разница? что должен озанчать токен, чтобы всё это работало правильно У ЛЮБОГО экземпляра этого типа? И чем тебе токен не адрес, в случае даже ассоциативной адресации, как в объектах языка JS, например?
Разница — принципиальна. Понятие адрес в программировании подразумевает определённую арифметику. В частности, возможность оперировать смещениями, что вы и пытаетесь делаеть, когда выдаёте за ликбез свои заблуждения.
V>Мне понятие "локальных переменных" преподавали когда-то на примере Паскаля. Не вижу принципиальных отличий от шарпа. Без сущности "стек", "стековые переменные", "фреймы стека" невозможно описать семантику дотнетной байт-машины.
Вы всё же почитайте это описание. Те стеки, которые фигурируют в описании семантики дотнетной байт-машины, это совсем не тот стек, которым вы управляете на ассемблере. А то, как вам преподавали понятие "локальных переменных", пусть остаётся на совести вашего преподавателя.
V>Ну мало ли что есть в современных оптимизаторах. Мы же оперируем семантикой, т.е. программа должна работать даже на таких процессорах, например, все регистры которого индексные, и предполагают исключительно косвенную адресацию, хоть в терминах программы мы исопльзуем непосредственную или прямую.
Совершенно верно. Поэтому семантика, которой мы оперируем, не имеет права опираться на потенциально устраняемые вещи типа "смещение относительно фрейма стека".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
V>>Ну дык проще простого. Если ты имел ввиду индексы переменных, то напиши код получения адресов стековых переменных в терминах MSIL и возьми разницу. Посмотри на полученный код. Вот тебе способ описать в одних терминах другие. G>Нет в IL способов определить "адрес стековых переменных". Переменные в стеке il могут оказать вовсе не в стеке в сгенерированном коде.
Вы тут сговорились, что ле?
using System;
namespace ConsoleApplication2 {
struct Probe { public int i; }
class Program {
unsafe static void Main(string[] args) {
var safeVar = new Probe();
Console.WriteLine(safeVar.i);
Probe* unsafeVar = &safeVar;
Console.WriteLine(unsafeVar->i);
}
}
}
Для обоих случаев используются одни и те же опкоды (я уже упоминал этот ключевой момент сообщением выше):
Понятие safe/unsafe работает ВНЕ байт-машины, а именно: обслуживается верификатором. И нужно исключительно для типобезопасности в угоду программиста и для корректной работы GC. О наличии GC, заметь, байт-машина даже не подозревает, это внешний, по отношению к ней, механизм.
ldloca.s index
Загружает в стек вычислений адрес локальной переменной с индексом index (короткая форма).
Определение семантики этой операции байт машины оперирует понятием "локальная переменная", считая его известным читателю, и оперирует термином "адрес", так же считая сей термин общеизвестным. А вы мне оба пытаетесь внушить, что нет ни локального фрейма памяти, ни адреса внутри фрейма. Смешно. Кстати, почему эти фреймы памяти образуют именно структуру "стек" во время работы программы, т.е. сущность с дисциплиной LIFO, но никак иначе — оставлю для самостоятельной медитации, это не сложно.
Ну и то, что адрес МОЖЕТ располагаться не на стеке — подобные половые трудности предлагаю держать при себе, они не интересуют программиста. Я писал долго для микроконтроллеров, где стек сильно ограничен, и там компилятор тоже использовал области глобальной памяти для размещения локальных переменных, т.е. эмулировал еще один стек, а именно стек данных, ввиду недостаточной глубины имеющегося, используемого только под стек возвратов. Но эти моменты программисту должны быть абсолютно до фени. Кстати, программист в любом случае должен считать, что стек возвратов и стек данных — это разные стеки, по крайней мере все компиляторы высокоуровневых ЯП обеспечивают такую семантику, даже если у целевого процессора всего один стек. Это прозрачно для программиста.
V>>Используется индекс элемента, какая фиг разница. Фрейм локальных переменных дотнета — это множество объектов, доступ к которым мы ведем по индексу. Имея только индекс элемента, но не имея базы — самого текущего фрейма, ты не сможешь получить переменную. В общем, ф-ия доступа к переменной — она от двух аргументов, фрейма и индекса: V>>el = F(frame, index);
G>Хрень ты написал. Переменная в стеке в IL может превратиться в обращение к регистру процессора. Именно поэтому IL не оперирует понятием адреса, чтобы был больший простор для генерируемого кода.
Ты бы что ле освежил свои познания IL, а то действительно хрень выходит. Можешь начать с приведенной ссылки, там слева все остальные опкоды. Мало-ли во что JIT превратит твою программу? С чего ты взял, что обязательно в регистр процессора? А если он вообще спекулятивно произведет расчеты и вернет сразу результат-константу в результате инлайнинга и распространения констант после этого инлайнинга? Занимаешься гаданиями, короче, не существенными для дела.
Здравствуйте, gandjustas, Вы писали:
G>Так это не не адрес переменной, который фрейм+смещение, а адрес некоторого объекта, который очевидно есть, так как объект размещен в памяти. При этом ссылка != указатель.
Во-первых, посмотри внимательно код. Речь шла об адресах переменных на стеке, поэтому код показывает взятие адреса именно стековой переменной. В этом случае адрес не может "просто быть", если сделать указанную ф-ию рекурсивной и каждый раз брать адрес локальной переменной, разве будет этот адрес одним и тем же? Или таки разным в каждом фрейме? Чувствуешь подвох, не? Код один и тот же, но для каждого фрейма будет свой адрес экземпляра одной и той же переменной. Я товарищу Sinclair предлагал чуть порассуждать, чтобы организовать работу такой машины без стека, или без явной его эмуляции (если в железке стека нет). Не выйдет.
G>Не понял фразы. Байт-машины нету вообще, есть абстракция, эта абстракция описывается ecma-335, в нем есть GC и верификация. Для указателей есть определенные правила, позволяющие им работать к таком окружении коректно.
Пока что мы работаем с двумя наличествующими в природе независимыми реализациями, где "абстракция" описывает как раз конкретную байт-машину, с точностью до расположения бит в инструкциях.
G>И вообще, указатель это адрес, но нельзя взять любой адрес и превратить его в указатель. Поэтому и адресной арифметики как таковой нету.
Во-первых можно взять любой адрес и превратить его таки в указатель.
Во-вторых, ты случайно не забыл еще, что есть адресная арифметика? Нельзя сравнивать или вычитать адреса из разных областей и разных типов. Например, если у нас есть некий массив элементов по значению, то адреса его элементов сравнивать и вычитать можно, т.к. эти адреса принадлежат одной области памяти и одному типу. Но, обрати внимание, разница указателей — это не кол-во байт м/у этими элементами, а кол-во элементов м/у указываемыми адресами на эти элементы. Вспомнил? Аналогично этому моменту я не понимаю, какие проблемы преобразования индекса в конкретный адрес, если есть информация о типах?
V>>ldloca.s index
V>>Загружает в стек вычислений адрес локальной переменной с индексом index (короткая форма).
V>>Определение семантики этой операции байт машины оперирует понятием "локальная переменная", считая его известным читателю, и оперирует термином "адрес", так же считая сей термин общеизвестным. G>Последнее неверно, оно просто не соотвествует тому что в Ecma написано.
Т.е. документация MSDN неверна?
G>Во время работы программы все это есть, но этим не надо и вообще говоря нельзя оперировать в терминах .NET. Ты не можешь получить фрейм стека и вычислить адрес переменной. Стековые переменные "адресуются" по индексу и все.
Ошибаешься. Я тебе пример привел, в чем проблема? Или сложности с прочтением?
V>>Ты бы что ле освежил свои познания IL, а то действительно хрень выходит. Можешь начать с приведенной ссылки, там слева все остальные опкоды. Мало-ли во что JIT превратит твою программу? С чего ты взял, что обязательно в регистр процессора? А если он вообще спекулятивно произведет расчеты и вернет сразу результат-константу в результате инлайнинга и распространения констант после этого инлайнинга? Занимаешься гаданиями, короче, не существенными для дела. G>Из-за флеймов на форуме я перечитываю excma-334 и 335 не реже раза в месяц, и тебе советую.
Читай себе. Но здесь пиши конкретно по делу.
G>Как переменная стека определяется в ассемблерном коде:
не важно
G>чаще всего фрейм стека хранится в регистре ebp и переменные в стеке являются смещениями, вроде ebp+4. Чтобы взять адрес объект в куче надо выполнить mov eax,[ebp+4], а чтобы обратиться к самому объекту надо еще раз обратиться по адресу, полученному в eax.
опять не важно
G>В терминах il операция вроде mov eax,[ebp+4] записывается как ldloc, причем JIT может решить что нет смысла выполнять много раз такую операция и положить локальную переменную в регистр.
Не важно с т.з. стандарта, важно другое, что ldloc означает загрузку локальной переменной, причем, эта операция должна работать непротиворечиво при произвольных вызовах метода, даже рекурсивных. А это не будет работать без формулы:
el = F(frame, index)
которая есть суть относительной адресации (или базовой)
G>То что ты написал уже выполняется после вычисления адреса переменной, и для получения адреса по ссылке не нужен фрейм стека.
Таки сложности с прочтением примера... так и думал.
Здравствуйте, vdimas, Вы писали:
V>>>Дык, не представляя способа адресации в каждом конкретном случае трудно получить представление об эффективности в этом месте. Да, обсуждаемые здесь языки таки поддерживают всевозможные способы адресации. L>>А эффективность тут причем?
V>Не зависит от способа адресации разве?
А способ адресации тут причем?
Я еще раз повторюсь: вы путаете понятия времени исполнения и понятия языка программирования.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Я пытался, но ты смотришь не на язык, а на стек, в то время как переменная — понятие языка а не стека и реализации.
V>Э нет, переменная — это "инструкция" высокоуровневого ЯП. Программу мы пишем не для времени компиляции, а именно для рантайма. И переменная — это инструкция управления/распределения памяти, где само фактическое распределение выполняется опираясь на типы значений, которые необходимо разместить в некоей памяти. И не надо пытаться строить такую невинность, что это всё далекие абстракции, которыми мы оперируем и не интересуемся реально происходящим. Дудки. Ты именно всегда непосредственно указываешь для переменной область памяти, в которой ее необходимо распределить: будь то глобальная область памяти, локальная или в области памяти, занимаемой объектом (т.е. в виде поля другого типа). Абтрагирование от конкретики происходит только на уровне типов, т.е. мы абстрагируемся лишь от размеров памяти, требуемых для значений (и как побочный эффект — защищаемся от неверной интерпретации этой памяти), больше ни от чего. Остальное мы указываем очень даже конкретно из расчета как нам конкретно надо, чтобы оно работало в рантайм.
А тебя не смущает, что в рантайме может не оказаться того, что ты так старательно и конкретно указывал?
Здравствуйте, Sinclair, Вы писали:
V>>Э нет, переменная — это "инструкция" высокоуровневого ЯП. Программу мы пишем не для времени компиляции, а именно для рантайма. И переменная — это инструкция управления/распределения памяти, где само фактическое распределение выполняется опираясь на типы значений, которые необходимо разместить в некоей памяти. И не надо пытаться строить такую невинность, что это всё далекие абстракции, которыми мы оперируем и не интересуемся реально происходящим. Дудки. Ты именно всегда непосредственно указываешь для переменной область памяти, в которой ее необходимо распределить: будь то глобальная область памяти, локальная или в области памяти, занимаемой объектом (т.е. в виде поля другого типа). Абтрагирование от конкретики происходит только на уровне типов, т.е. мы абстрагируемся лишь от размеров памяти, требуемых для значений (и как побочный эффект — защищаемся от неверной интерпретации этой памяти), больше ни от чего. Остальное мы указываем очень даже конкретно из расчета как нам конкретно надо, чтобы оно работало в рантайм. S>Это неконструктивная позиция. S>Потому, что вот я указал очень конкретно, где что размещать: S>
S>public void Test()
S>{
S> int i = 42;
S>
S>Где у нас i? В стеке? S>Как бы не так! Потому что дальше (через 100 строк) я пишу:
S>
Тогда, извините, ликбез. Замыкания бывают двух типов: by name и by value. Во втором случае, согласно определению, замыкание создает копии локальных переменных, входящих в замыкание. Обрати особое внимание на то, что те переменные, которые были локальны в исходном контексте, будут локальными и для замыкания, в отличие от глобальных или иных переменных. Но замыкание by name, по определению, создает shared значение, доступное по имени как из замыкания, так и из исходного контекста. Поэтому, приводя пример классического замыкания by name, ты лишь подтверждаешь исходный тезис.
Ты же сам включил целевую переменную именно в этот вид замыкания, это же не компилятор за тебя сделал. Коль ты указал ему "инструкцию" замыкания некоей переменной, он послушно ее разместит согласно определения поддерживаемого языком типа замыкания. Т.е. для твоего случая так, чтобы эти данные стали shared м/у контекстом замыкания и исходным контекстом. И поверь, он обеспечит эту семантику даже для случая, когда все прооптимизирует нафик и реально никакого отдельного shared-state не будет (например, в результате escape-анализа). Но т.к. заданная тобой семантика сохраняется, эти вещи для тебя прозрачны.
S>Семантика переменной и размещение переменной — штуки очень разные. Не надо их смешивать.
Покажи, почему разные? Я настаиваю, что семантика переменной чуть более чем полностью определяется ее размещением... ну кроме случая однопоточных программ, где семантика локальной и глобальной переменной в некоторых сценариях одинакова. Но это тоже известно и тоже используется, эффективности ради.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Ну т.е. ты признаешь что между рантаймом и ЯВУ параллели может не быть, тем не менее настаиваешь на том, что бы именно по рантайму делать выводы о сущностях ЯВУ?
V>Не так. Оптимизация приемами суперкомпиляция — это скорее рантайм, а не compile-time. Посмотри рядом Синклеру чуть подробней обрисовал: http://www.rsdn.ru/forum/philosophy/4523815.1.aspx
Для того что бы выкидывать поля, переменные, структуры, функции и т.п. не нужна никакая суперкомпиляция и рантаймы. Даже если оптимизация выполнена приемами суперкомпиляции, это ничего не меняет в отношении исходного кода и двоичного.
Здравствуйте, vdimas, Вы писали:
V>И какие проблемы? На некоторых архитектурах привычные тебе вещи вообще делаются задом наперед и с очень многими ограничениями. В этих случаях тем более надо понимать, что происходит, чтобы лажи не напороть.
Проблемы — очень простые. Вы при обсуждении вопросов одного уровня абстракции, начинаете оперировать понятиями другого уровня абстракции. Это показывает отсутствие чёткого разделения слоёв.
V>Абстракция позволяет абстрагироваться от подробностей, согласен. Но если ты знаешь, например, что замыкание создаст объект-локальный-фрейм в куче, потом делегат, то будешь пытаться писать код так, чтобы это замыкание не создавалось внути критического цикла мильон раз. Иначе твоя программа банально не взлетит. Ты просто не будешь вылезать из профайлера каждые следующие десяток накиданных строчек кода, работать некогда будет.
Я правильно понимаю, что вы считаете использование профайлера для оптимизации производительности плохой идеей?
Лично я — ровно наоборот. 90% предположений об узких местах программы, сделанных на основе умственной модели нижних слоёв архитектуры, оказываются неверными.
V>Даже уже MSIL не важен, достаточно более крупно: память в куче, в поле объекта, локальная на стеке, статическая. Достаточно иметь представление, какие имеем затраты для каждого из популярных сценариев и можно начинать писать адекватные программы.
Ой, как интересно. А почему вы не включаете сюда значительно более важные для производительности вещи — например Interlocked.Increment() по сравнению с a++; или Thread.Sleep(0) vs Thread.Yield() vs Thread.SpinWait()?
Почему вас не интересуют вопросы устройства L1 и L2 кэшей и связанные с ними вопросы выравнивания?
Нет никаких симптомов интереса к особенностям поведения запиненных блоков памяти?
Вы серъёзно полагаете, что для производительности программы разница между переменными, размещёнными в разных "видах" памяти, в вашей классификации, более принципиальна, чем разница между методами доступа к этим переменным?
V>Да ты не можешь ни за чем следить, если не будешь понимать взаимосвязь различных уровней абстракции.
Понимание взаимосвязи в первую очередь требует понимания границ между этими уровнями. Пока для вас все уровни сводятся к LEA EAX, этого понимания не будет.
V>Какие такие другие платформы? Сколько платформ/языков/поколений ты сменил за время своего стажа в IT?
Языков — да штук с десяток наверное. Платформ — это как считать.
V>Откуда ты вообще мог взять такое странное мнение? Мне пока кажется, что ты споришь с надуманной для самого себя "потенциальной проблемой", которой реально нет и не было.
Да я эту "потенциальную проблему" наблюдаю прямо сейчас — она бесплодно спорит со мной в этом топике.
V>Это если не владеть реляционной алгеброй и не изучать основные приемы отображения деклараций SQL на примитивы реляционной алгебры в пору своего образования. Тогда план запроса будет для тебя просто темный лес, разумеется, и что делать с индексами, когда делать и почему именно так — ты никогда не поймешь... это же не уровень SQL, это же уже не та абстракция, правильно?
Простите, но где вы нашли индексы в реляционной алгебре? Вы точно понимаете границы между алгеброй, SQL, и логикой работы query optimizer? Или для вас реляционная алгебра включает всё это как монолитный блок?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Простите, а вы здесь переменной называете что? Variable в терминах спецификации C#? Или какую-то другую сущность, которая внезапно существует одновременно на разных уровнях абстракции?
в данном случае, переменной называется сущность, которая остается от 'Variable в терминах спецификации C#' при переходе между всеми абстракциями
S>Что вы называете "локальным адресом"? Чем он отличается от "нелокального"? S>Заблуждения про то, что контекстом статической переменной является сборка я обсуждать не буду.
именно сборка, потому что если одну и ту же сборку удастся загрузить с другим имененем (например, пропатчив ее), то переменных будет две.
DG>>именно сборка, потому что если одну и ту же сборку удастся загрузить с другим имененем (например, пропатчив ее), то переменных будет две. S>Ок, ладно, вы на верном пути, хотя формулировка недостаточно строгая.
по крайней мере строже и главное верно, в отличии от утверждения некого Sinclair-а (который утверждал нестрого и неверно одновременно) > Семантика полей в дотнете такова, что статическое поле хранит ровно одно значение в пределах домена
хотя вот такой код показывает, что статических переменных в одном домене вдруг две:
static void Main(string[] args)
{
ClassLibrary1.Class1.X = 5;
Console.WriteLine("Значение в instance 1: {0}", ClassLibrary1.Class1.X);
if (!Directory.Exists("Other"))
Directory.CreateDirectory("Other");
var location = typeof(ClassLibrary1.Class1).Assembly.Location;
var newFilename ="Other/" + Path.GetFileName(location);
File.Copy(location, newFilename, true);
Console.WriteLine("Загружаем второй instance сборки");
var assembly = System.Reflection.Assembly.LoadFrom(newFilename);
var x = assembly.GetType("ClassLibrary1.Class1").GetField("X");
Console.WriteLine("Значение в instance 2: {0}", x.GetValue(null));
x.SetValue(null, 10);
Console.WriteLine("Меняем значение в instance 2");
Console.WriteLine("Значение в instance 1: {0}", ClassLibrary1.Class1.X);
Console.WriteLine("Значение в instance 2: {0}", x.GetValue(null));
}
код сборки
namespace ClassLibrary1
{
public class Class1
{
public static int X;
}
}
выдача
Значение в instance 1: 5
Загружаем второй instance сборки
Значение в instance 2: 0
Меняем значение в instance 2
Значение в instance 1: 5
Значение в instance 2: 10
если в рамках этого треда ты мне за каждое нестрогое и при этом неверное утверждение давал бы доллар, я бы уже был богаче Гейтса.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, vdimas, Вы писали:
V>>И какие проблемы? На некоторых архитектурах привычные тебе вещи вообще делаются задом наперед и с очень многими ограничениями. В этих случаях тем более надо понимать, что происходит, чтобы лажи не напороть. S>Проблемы — очень простые. Вы при обсуждении вопросов одного уровня абстракции, начинаете оперировать понятиями другого уровня абстракции. Это показывает отсутствие чёткого разделения слоёв.
А не преподавали "четкого разделения слоев". И самостоятельно в учебниках не видел. И ты пока тоже ничего не сформулировал. И под вопросом вообще разделение слоев абстракций, бо в классике абстракции — это градиент, коль не задано обратное, где на одном из полюсов используется минимум деталей, а на другом максимум.
Нет никаких слоев, заданных свыше. "Слои абстракций" бывают в рамках конкретного проекта/продукта, и они могут выбираться на усмотрение разработчиков.
Я кажется понял твою проблему. Возьми известный пример чистой абстракции — "схема электрическая функциональная". Она абстрагируется от конкретных номиналов элементов, но сама может быть расписана с любой степенью подробности, даже до степени полного соответствия схемы электрической принципиальной. А может — наоборот, очень "крупными" мазками отображать происходящее. Никаких ограничений на этот счет нет. Назначение этой абстракции ровно одно — объяснять суть происходящего, опуская несущественные детали. А ты почему-то решил, что абстракции нужны исключительно для сокрытия деталей. Это не совсем одно и то же. ИМХО, тут сработала привычка видеть абстракции в виде пары: инкапсуляция — публичный интерфейс. Этого мало для начала оперирования термином.
V>>Ты просто не будешь вылезать из профайлера каждые следующие десяток накиданных строчек кода, работать некогда будет. S>Я правильно понимаю, что вы считаете использование профайлера для оптимизации производительности плохой идеей?
А вы тоже младенцев по утрам есть перестали?.. Отборная, однако...
Ладно. Плохой признак, когда к профайлеру приходится часто обращаться. Ну и по профайлерам высказывался как-то... Если всерьез работать над производительностью, то профайлеры способны показать самое первое приближение. Уместнее всего для изучения проблем в чужом коде. постоянное исопльзование для своего — это клиника и неумение работать над оптимизацией. С помощью только лишь профайлера всерьез ты всё-равно ничего всерьез не наоптимизируешь, тем более, что они безбожно врут по самым критическим моментам, например по переключениям потоков или издержкам кеша процессора. Настоящая оптимизация проводится по специально подготовленным тестам на производительность. В любом случае, чтобы разработчик мог что-то соптимизировать, он должен понимать происходящее, иначе не поможет ни профайлер, ни тесты на производительность. Ну, увидел он, что такая-то операция занимает столько-то... Ну и дальше что? Идей-то никаких...
S>Лично я — ровно наоборот. 90% предположений об узких местах программы, сделанных на основе умственной модели нижних слоёв архитектуры, оказываются неверными.
Мде? ну я бы не стал этим хвастаться. У меня в 100% случаев первоначальные предположения совпадают как с с данными профайлера, так и с разницей тестов на производительности... Приемов-то оптимизации не так много в природе, овладел ими еще в прошлом веке. И обратное тоже верно — потенциальных типов узких мест (грубо говоря — антипаттернов) очень мало в природе. И они сразу бросаются в глаза. Профалер тут хорош лишь в деле расстановки приоритетов перед началом зачистки этого мусора и то, весьма приблизительно. Бо в конкретном некоем сценарии профалер покажет одну частоту вызовов "узких мест" (например, маленькую), а реально она может вызываться чуть чаще... Поэтому когда речь идет всерьез, то собирается статистика в логах прямо из "боевого" применения, где ни о каких профайлерах речи быть не может...
Вообще, я довольно часто вижу на этом форуме, что народ приписывает профайлерам странные вещи и не понимает толком, для чего они нужны.
V>>Даже уже MSIL не важен, достаточно более крупно: память в куче, в поле объекта, локальная на стеке, статическая. Достаточно иметь представление, какие имеем затраты для каждого из популярных сценариев и можно начинать писать адекватные программы. S>Ой, как интересно. А почему вы не включаете сюда значительно более важные для производительности вещи — например Interlocked.Increment() по сравнению с a++; или Thread.Sleep(0) vs Thread.Yield() vs Thread.SpinWait()?
Наверно, потому что в первую очередь при поднятии производительности умудряюсь множество shared-сценариев свести к local...
Многопоточность хороша в меру: чем в меньшее число потоков удается решить задачу, тем эффективнее конечная система на современных многопроцессорных машинах. И почему я все эти вещи не упоминал? Наверно потому, что там, где у меня идут lock-free алгоритмы, там дотнета нет и близко. В дотнете есть свои эффективные многопоточные паттерны, например, read-copy-update во многих сценариях показывает многократный профит в сравнении с ReadWriteLockSlim, а для этого паттерна не нужен ни Interlocked.Increment(), ни даже Interlocked.Exchange(). А вместо откровенного уровня "в лоб" решения SpinWait() (то бишь asm pause, и надо тоже знать, кстате, почему именно так), всяко полезней пользовать interlocked-алгоритмы. А где без таких спин-ожиданий никак, это сигнал начинать прикручивать фиберы.
Оставшиеся приведенные Thread.Sleep(0) и Thread.Yield() стараюсь напрямую не использовать. Вернее, стараюсь так обыгрывать многопоточную логику, чтобы минимизировать эти вмешательства в работу планировщика потоков. Само применение этих методов говорит о том, что многопоточная часть задачи выполнена спустя рукава, не думая. Твой код получил квант времени, хотя не должен был, и уже поздно что-то исправлять, бо произошла тяжелая операция переключения контекста потока. У меня для кода, в котором я такое вижу — сразу загорается красная лампочка "тут были нубы, надо всё проверить". Я уже молчу о том, что дотнетный Monitor.Enter() и соответствующая конструкция lock() малость неэффективны, поэтому Thread.Yield() можно пользовать разве что собственного мьютекса-велосипеда. Только зачем велосипедить-то? Можно пользовать готовый CRITICAL_SECTION через pInvoke.
S>Почему вас не интересуют вопросы устройства L1 и L2 кэшей и связанные с ними вопросы выравнивания? S>Нет никаких симптомов интереса к особенностям поведения запиненных блоков памяти?
Потому что этот уровень настолько далеко отстоит в сравнении с затратами на создание делегата и глобальной блокировкой общего мьютекса на все потоки... что это будет явная профанация, рядом с дотнетными замыканиями обсуждать такие вещи. Просто ты ведь не в курсе, наверно, про эту общую для всех потоков блокировку при создании экземпляра делегата, помимо собственно затратной операции создания делегата, отсюда неуместные рассуждения о приемах, которые на несколько порядков дают меньший прирост, чем простое избавление от делегата... (хоть они тоже в ходу в кач-ве приемов оптимизации.. но уже на совсем другой итерации работ по оптимизации, даже не второй и не третьей)... ИМХО, отсюда и 90% твоих ошибок в первоначальных предположениях. Можно продолжать игнорировать тонкости реализации и дальше.
S>Вы серъёзно полагаете, что для производительности программы разница между переменными, размещёнными в разных "видах" памяти, в вашей классификации, более принципиальна, чем разница между методами доступа к этим переменным?
Ага, что более важное — круглое или зеленое? Коль мы поставим все переменные в одинаковый сценарий, например, однопоточный, то ответ да. Накладные расходы однаковых сценариев сказываются на операцию доступа одинаково, и является той самой паразитной постоянной составляющей при измерениях. Напротив, когда будем оптимизировать сценарий доступа, то постараюсь минимизировать влияние размещение переменной, т.е. сделать как минимум одинаковым (неважно каким). В общем, ортогональные и прочие независимые вещи стоит рассматривать и измерять, разумеется, независимо.
V>>Да ты не можешь ни за чем следить, если не будешь понимать взаимосвязь различных уровней абстракции. S>Понимание взаимосвязи в первую очередь требует понимания границ между этими уровнями. Пока для вас все уровни сводятся к LEA EAX, этого понимания не будет.
У меня нет границ вообще. Для меня даже LEA EAX порой слишком высокая абстракция, коль до этого уровня доходит, бо тут уже важна предыстория команд. В общем, нету никаких границ и не было никогда, это ты решил поизобретать тут. Конкретный уровень оперируемых абстракций должен соответствовать характеру работы разработчика. Например, разработка и последующая шлифовка некоторого алгоритма — это очень разные по характеру задачи, поэтому уровень абстракции модели происходящего, которую надо держать при этом в голове, будет сильно отличаться.
V>>Какие такие другие платформы? Сколько платформ/языков/поколений ты сменил за время своего стажа в IT? S>Языков — да штук с десяток наверное. Платформ — это как считать.
Ну вот так, управляемый можно считать за платформу. Каждую аппаратную — тоже. Но это я не для конкурса пиписек спросил, скорее риторически, бо ты делаешь очень странные предположения на мой счет в связке с архитектурой x86, зачем-то. А в лице меня — похоже что и на остальных, кто будет с тобой не согласен.
V>>Откуда ты вообще мог взять такое странное мнение? Мне пока кажется, что ты споришь с надуманной для самого себя "потенциальной проблемой", которой реально нет и не было. S>Да я эту "потенциальную проблему" наблюдаю прямо сейчас — она бесплодно спорит со мной в этом топике.
Слова, слова... Не люблю я слово "слив", но ты уже очень близок, с подобными аргументами.
V>>Это если не владеть реляционной алгеброй и не изучать основные приемы отображения деклараций SQL на примитивы реляционной алгебры в пору своего образования. Тогда план запроса будет для тебя просто темный лес, разумеется, и что делать с индексами, когда делать и почему именно так — ты никогда не поймешь... это же не уровень SQL, это же уже не та абстракция, правильно? S>Простите, но где вы нашли индексы в реляционной алгебре?
Про индексы речь шла в деле понимания плана запросов. А сам план запросов как раз в терминах реляционной алгебры отображается. И да, когда изучают реляционную алгебру, то непременно проходят операцию "проекция", сохранением результата которой и является индекс в классике. Так не стоит упускать из виду, что реляционная алгебра существует не сама по себе, а как инструмент над реляционной моделью, т.е. другие свои характеристики, например уникальность/неуникальность, индексы берут из раздела реляционной модели данных, которая, анпример, оперирует понятиями основного и альтернативных ключей. И да, понятие индекса идет вместе с реляционными базами данных, для которых, собственно, и была разработана реляционная модель.
S>Вы точно понимаете границы между алгеброй, SQL, и логикой работы query optimizer? Или для вас реляционная алгебра включает всё это как монолитный блок?
Несвязный набор слов. Одно использует другое. SQL оперирует терминами реляционного исчисления, но стоимость операций реляционного исчисления недетерминирована. Наоборот, в терминах реляционной алгебры стоимости операций являются вычислимыми. Вот тебе основной инструмент оптимизатора. Как взаимосвязь всех этих моментов конкретно в моей голове представляется, в виде ли "монолитного блока" (С), фрактала, направленного графа или нечеткой логики — к теме не имеет никакого отношения.
DG>>для появления эквивалентности необходимо округлять на epsilon перед сравнением. S>Не понял, это как?
есть стандартная формула Round(x, точность) = точность * Round(x/точность)
S>>> Google: No results found for "нестрогое отношение эквивалентности"
DG>>тогда ищи что такое отношение толерантности S>А какое отношение имеет толерантность к идентичности?
все тоже самое, что необходим пруфлинк, что идентичность должна быть Единой для всего пространства объектов в ООП.
если берется сумма множеств с отношениями эквивалентности на каждом, то суммарное множество обладает в общем случае лишь отношением толерантности.
тоже самое с идентичностью, если берется сумма множеств с отношением идентичности на каждом, то суммарное множество обладает лишь свойством нетранзитивной идентичности.
это кстати активно используется в реальных ООП-языках, например, для null. нетипизированный null (или константный null) идентичен типизированному null, но null-и разных типов не идентичны друг другу. и это полностью соответствует выше написаному (внутри отдельных множеств строгая идентичность и эквивалентность вводится, но поверх всех множества объекта уже нет): внутри объектов одного типа идентичность транзитивная, но при этом между объектами разных типов транзитивность уже нарушается. соответственно также может вводится типы, для которых строгая идентичность есть только на подмножествах объектов данного типа.
Здравствуйте, Sinclair, Вы писали:
V>>Нет никаких слоев, заданных свыше. "Слои абстракций" бывают в рамках конкретного проекта/продукта, и они могут выбираться на усмотрение разработчиков. S>Конечно. Тем не менее, границы между слоями (в приличной архитектуре) чётко выражены.
Да, но не заданы свыше. Это принципиально.
S>ограничений на этот счет нет. Назначение этой абстракции ровно одно — объяснять суть происходящего, опуская несущественные детали. А ты почему-то решил, что абстракции нужны исключительно для сокрытия деталей. S>Нет, я так не решил.
V>>Ладно. Плохой признак, когда к профайлеру приходится часто обращаться. S>Конечно плохой — это означает, что вы профилируете невовремя, т.е. занимаетесь premature optimization. S>Я, кстати, под профайлером в данном контексте понимаю не конкретное приложение, а вообще измерение производительности — это чтобы избежать ненужных споров. Я полностью согласен с вашей критикой профайлеров и с тем, что специальным образом проведённые тесты — это круто и правильно. S>А вот с тем, что умственное моделирование производительности лучше, чем измерение, я не соглашусь.
Ну таки при некотором навыке экономит невообразимую массу времени во время разработки. И во время поиска узких мест у коллег тоже. Там не rocket-science вовсе... ты же обратил внимание, что мне сам факт обсуждения подобных вещей кажется странным? Это же обсуждение самой необходимости быть специалистом своего дела, или забить по принципу "и так сойдет"...
V>>Мде? ну я бы не стал этим хвастаться. У меня в 100% случаев первоначальные предположения совпадают как с с данными профайлера, так и с разницей тестов на производительности... S>Искренне завидую. Жаль, что таких людей в природе больше нет.
Есть — коллеги. Смотрел на сделанные ими преобразования недавно в критичном общем коде... я бы сделал один-в-один с точностью до несущественных подробностей. Могу лишь предположить, что тебе по работе всё, что мы тут обсуждаем, банально не очень нужно. А у нас она из этого состоит процентов на 90% или больше. Отсюда соответственные привычки и навыки.
V>>Приемов-то оптимизации не так много в природе, овладел ими еще в прошлом веке. И обратное тоже верно — потенциальных типов узких мест (грубо говоря — антипаттернов) очень мало в природе. И они сразу бросаются в глаза. Профалер тут хорош лишь в деле расстановки приоритетов перед началом зачистки этого мусора и то, весьма приблизительно. Бо в конкретном некоем сценарии профалер покажет одну частоту вызовов "узких мест" (например, маленькую), а реально она может вызываться чуть чаще... Поэтому когда речь идет всерьез, то собирается статистика в логах прямо из "боевого" применения, где ни о каких профайлерах речи быть не может... S>Можете продемонстрировать на простом примере? Вот в этой несложной программе, где именно боттлнек (чур, профайлер не запускать):
S>Это программа для игры в скрэббл. Она грузит примерно двухмегабайтный файл со словарём английских слов (путь к файлу захардкожен) и выполняет поиск слова, которое можно собрать из заданных ей на входе букв (нужно использовать все предоставленные буквы). S>Она чудовищно неоптимальна.
Скажу так, что ПЕРЕД началом оптимизаций, программу необходимо переписать. Например, читать из файла лишь однажды, прочитанные строки отсортировать по длине, а вместо генерации всех вариантов ReplaceQuestionMarks написать алгоритм непосредственного сравнения паттернов с "??". Т.е. для начала сделать преобразования алгоритмов в терминах O(n). И только после доработки алгоритмов можно приступать шлифовать коэффициент K при O(n). Это общая практика. Конечно, под "шлифовкой" алгоритмов я имею ввиду шлифовку технической части, а не самантической, т.е. не подмену самого алгоритма. Поиск удачных алгоритмов всегда гут, этот момент вроде бы даже тут разногласий не вызывает, правильно? Просто удачность алгоритма зависит от характера данных, например подаются данные по однму элементу, пачками или как еще. Иногда бывает так, что коэф при O(n) всяко важнее самого O(n) коль имеем тяжелые затраты на вызов, как в случае создания делегатов в дотнете в цикле или глубоких потенциальных вложенных енумераторов, как в твоем примере в злосчастном ReplaceQuestionMarks. Т.е. оптимизировать я бы взялся не эту, а преобразованную программу. Как и сказал выше, профайлер тут нужен для того, чтобы выяснить приоритет, какое из этих двух преобразований стоит сделать первым. Ну и опять же, надо понимать, что происходит даже в случае использования профайлера, т.е. заранее видеть потенциальное узкое место. Чтобы наткнуться на ReplaceQuestionMarks надо подать достаточно длинное слово со многими ??. Подай туда слово из трех букв — и ты ведь ничего не заметишь, какой бы волшебный профайлер не был.
S>Не, я не в курсе про эту общую для всех потоков блокировку. А где можно про неё прочитать? Уж очень фантастически звучит.
Это можно в тестах выяснить, зачем что читать? Как раз тонкости реализаций не всегда описаны. Берем 2 независимые от вызовов операции, одинаковые по стоимости в случае одного потока. Затем прогоняем их на многопроцессорной машине из многих потоков, строим график и видим, какая операция масштабируется фактически линейно, а какая нет.
V>>Про индексы речь шла в деле понимания плана запросов. А сам план запросов как раз в терминах реляционной алгебры отображается. S>Неужели? Ну, значит, моё понимание РА сильно отстало от жизни. Когда я в последний раз к ней обращался, там не было никаких Bookmark Lookup, Table Rewind, Clustered Index Seek и прочего.
А ты понял значение этих терминов? Bookmark Lookup — это восстановление соответствия м/у выделенным индексом и индексируемыми строками. Откуда берутся индексы — уже говорил выше. Clustered Index Seek — это есть операция "выборка" по проекции или "ограничение". "Clustered" — это подробность хранения индекса, идет из раздела реляционных баз данных. Я уже упоминал, что реляционные базы, реляционная модель, реляционное исчисление и реляционная алгебра связаны друг с другом. Матаппарат делиться на разделы, ок, ну разделы и разделы себе... Но использовать одно без другого бессмысленно, ведь реляционная модель была придумана для реляционных баз, а реляционное исчисление и реляционная алгебра были введены как инструмент над реляционной моделью. А вовсе не "сами по себе".
V>>И да, когда изучают реляционную алгебру, то непременно проходят операцию "проекция", сохранением результата которой и является индекс в классике. S>Простите, но это чушь. То, что получается в результате выполнения проекции, даже если его сохранить, никак не может быть индексом в классике. Если вам очень хочется поспорить про это — попробуйте применить такой "индекс" для оптимизации какого-нибудь запроса.
Таки настаиваю. Понимаешь, индекс можно построить даже по данным, которые не поддерживают операцию сравнения, хоть этого нельзя конкретно в MS SQL, но это лишь подробности MS SQL. Принципиально в таком индексе будет то, что объем данных проекции может быть гораздо меньше объема всех данных, поэтому операция выборки/ограничения по индексу может быть выполнена многократно эффективнее, чем по всем исходным данным. Вот так может приниматься решение — делать индекс кластерным или некластерным.
S>Скажем, вот у нас табличка
S>
S>create table person(id int identity primary key, name varchar(max) not null, gender char(1) not null, picture )
S>
S>Мы хотим оптимизировать запрос S>
S>select id from person where name = 'vdimas'
S>
S>Расскажите мне, результат какой операции "проекция" тут поможет так же, как S>
S>create index ByName on person(name, id)
S>
Еще раз большими буквами — любой некластерный индекс — это и есть проекция. В классике индексы некластерные изначально. Просто в MS SQL ввиду особенностей хранения блобов кластерные индексы оч популярны.
Я тебе скажу так, в достаточно большой системе, с многими миллионами записей движений и сотнеями справочников, одно лишь только изменение суррогатных ключей с типа int на shortint в справочниках и оформление индексов как некластерных у справочников, где записи достаточно большие (много полей) подняло производительность более чем в четверо. Вот зачем нужна проекция при построении индекса — это снижение объема перелопачиваемых данных при операциях над таблицами, проводимыми по этому индексу/ключу (фактически все операции из РА).
S>Бррр. Опять каша. Реляционная алгебра — это раздел математики, достаточно строго определённый. Она работает с реляциями.
Это прикланой раздел, который, каки любой прикадной раздел, что-то обслуживает. Конерктно реляционная алгебра была разработана для обслуживания реляционной модели. И она не может жить ВНЕ реляционной модели.
V>>Несвязный набор слов. Одно использует другое. SQL оперирует терминами реляционного исчисления, но стоимость операций реляционного исчисления недетерминирована. S>Это у вас несвязный набор слов. SQL отклоняется от реляционной алгебры, т.к. представляет компромисс между математической строгостью и вопросами реальной производительности. Терминами реляционного исчисления SQL никак не оперирует:
Наверно не понимаешь, что есть реляционное исчисление, а что есть реляционная алгебра, так? Это совсем не одно и то же.
S>Вопросы стоимости операций появляются только в тот момент, когда мы заменяем абстрактные операции расширенной РА в логическом плане запроса конкретными операциями физического плана запроса. Именно в этот момент появляется простор для оптимизаций, т.к. одному и тому же логическому плану запроса может соответствовать много различных физических планов запроса, отличающихся стоимостью.
Я не знаю, что есть логическое, а что есть физическое в твоем понимании? Использование разного порядка сканирования индексов — это физическое отличие или логическое? А ведь разные вещи, хотя с т.з. реляционного исчисления — это не имеет значения, но с т.з. реляционной алгебры — это разная последовательность императивных операций над разными таблицами-индексами. Я в свое время нарешался на практиках задач по составлению реляционных алгоритмов, заданных реляционным исчислением как условием (это почти SQL, только математический), что аж тошнило. И для случая отдельных индексов в т.ч. Индексы в этих задачах рассматриваются как отдельное отношение, где кортеж целиком совпадает со своим основным (и единственным) ключом.
DG>>>определи, пожалуйста, раз это легко сделать.
S>>Пардон, с наскоку не получилось сравнить структуры побитово.
DG>тогда из этого следует, что Ecma identity не может использоваться как функция идентификации объектов, потому что она нарушает инкапсуляцию объектов.
Для структур identity определяется по другому и оно не является identity в смысле ООП
Здравствуйте, DarkGray, Вы писали:
DG>я уже давал ссылку на определение, в котором явно сказано, что разницы ссылок не следует, что объект не тот же самый
В общем случае да, но для CLR идентичность и есть равенство ссылок.
S>Но запуск профайлера всё равно был бы дешевле и точнее.
это верно(особенно последнее) только при совпадении множества факторов:
1. совпадают окружения при запуске профайлера и реальное окружение.
2. совпадает набор запросов подаваемый программе под профайлером и набор запросов прогоняемый в реальном окружение.
3. профайлер умеет собирать относительную (условную) статистику (или это учтено при в сценарии использования профайлера)
4. правильно зафиксировано и учтено при профайлинге, что именно оптимизируется: среднее время запроса, верхняя граница обработки запроса, достаточность быстродействия и т.д.
зы
в моем понимании, хороший программист должен уметь строить модель узких мест своих программы прямо по коду, используя профайлер лишь для проверки и корректировки своего понимания
DG>вычислительное узкое место в этом сравнении DG>
DG> return from line in FileLines(dictionary)
DG> where line.Length == originalRack.Length
DG> where racks.Contains(Canonicalize(line))
DG> select line;
DG>
DG>сложность: 27 вызовов * кол-во слов в словаре с заданной длиной * (sort слова + (1+26 * кол-во '?') сравнений слов) DG>И скорее всего именно поэтому его уже пытались оптимизировать (вынесен racks и добавлено сравнение длин). DG>racks стоит заменить на Set/Dictionary вместо массива
А стоимость самого получения racks не изучал? Мне навскидку показалось, что размер racks будет относительно небольшой в большинстве случаев (сотни элементов в среднем), но дорогой в получении.
G>>* Set meaningful, measurable, customer-focused goals.
G>>* Write the code to be as clear and correct as possible.
G>>* Carefully measure your performance against your goals.
G>>* Did you meet your goal? Great! Don't waste any time on performance analysis. Spend your valuable time on features, documentation, bug fixing, robustness, security, whatever.
G>>* If you did not meet your goal, use tools to discover what the worst-performing fixable thing is, and fix it.
DG>не вижу где написано, что программист не должен уметь оценивать производительность своего кода без профайлера.
Не написано что должен, следовательно не должен. Элементарная логика.
Более того, не всегда приходится свой код оптимизировать.
G>>Если в коде еще есть ленивость и\или асинхронность, то единственный способ — мерить. Даже предполагать что-то нельзя.
DG>это лишь означает, что некоторые не умеют готовить ленивость или асинхроность.
Счегобы? Многие умеют писать программы используя ленивость и асинхронность. Далеко не все могут предположить по внешнему виду время работы.
Пример на форуме показал это очень явно. Даже местные гуры перформанса не смогли сходу обнаружить проблему. Так в коде не было ни ленивости, ни асинхронности, ни десятка уровней косвенности.
DG>зы DG>и на всякий случай напишу очевидные вещи: DG>1. через профайлер можно прогнать лишь ограниченное кол-во сценариев, которое много меньше, чем поддерживаемое программой кол-во сценариев DG>2. bottleneck необходимо уметь обнаруживать до того, как на него наткнутся в реальном применении (особенно это актуально для защиты от DDOS)
Еще раз читай то что я процитировал. Первый пункт.
никакого подробного разбора там нет, есть лишь общие слова — которые правильные с точки зрения бизнеса, но имеют отдаленное отношение к задаче оптимизации (когда необходимость в ней действительно возникает).
Здравствуйте, vdimas, Вы писали:
V>Да не мое, чего уж там... V>Меня тогда еще в проекте не было, когда это определение уже было, в Вики дается без изменений оригинала.
Блин, выражение "меня ещё в проекте не было" на программистском форуме читается весьма неоднозначно.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
G>потом я показал как в их случае надо мерить. Вот померили и сразу нашлись узкие места. G>Тут же каждый второй гуру говорит что нужны тайные знания,
в первой строчке, ты говоришь что: челы не знали что делать, но ты им принес "тайные знания", и они сразу проблему решили.
во второй сторочке, ты говоришь, что "тайных знаний" не бывает.
так ты определись:
либо это не тайные знания — и тогда их знают все, но тогда непонятно почему без тебя не смогли справиться,
либо эти знания имеют не все, тогда они тайные
G>Тут же каждый второй гуру говорит что нужны тайные знания, а на практике 99% производительности вытягивается именно так. А только 1% требует "щаманства".
Это если тыкать LINQ и линейные пробежки направо и налево, т.е. заведомо иметь потенциальный запас по увеличению эффективности на пару порядков, тоды да... а если прога уже довольно-таки неплоха, но надо еще в несколько раз быстрее... посмотрел бы я на то, как бы ты "толковал" показания профайлера. Без идей в плане того, куда двигать дальше, показания профайлера превращаются в бесполезный набор цифр. Это то, что я пытаюсь донести.
В приведенном Липпертом примере автор пошагово порет фигню, мягко говоря, порождая код, который все-равно надо будет выкинуть через несколько итераций. Почему нельзя рассмотреть алгоритм целиком? Зачем оптимизировать куски заведомо неэффективного алгоритма, коль можно сразу применить более эффективный алгоритм? Это же какой-то наёп, сорри, а не полезные советы. Они пойдут только какому-нить новичку, который будет раскидывать коровьи лепешки буквально везде по коду. Только тогда подобный алгоритм будет хоть как-то полезен для этого вырожденного случая, чтобы программа хоть как-то задышала, т.е. перешла из стадии макета в стадию чего-то полезного.
G>Отсутствие каких-либо цифр не лучше. Попытка делать хоть какие-то выводы в таком случае — шаманство.
А где ты видел "отсутствие каких-либо цифр"? Речь шла зашла о сценариях применения профайлеров. В любом случае дотнетный профайлер не поможет, когда доходит до уровня игр с разной грануляцией блокировок, переделкой алгоритмов в многопоточные или обратно и т.д., борьбой с издержкой кешей, затрат на переключения контекстов и т.д. Тут уместны уже нейтивные от интел или амд для нейтивных же программ.
Здравствуйте, DarkGray, Вы писали:
G>>потом я показал как в их случае надо мерить. Вот померили и сразу нашлись узкие места. G>>Тут же каждый второй гуру говорит что нужны тайные знания,
DG>в первой строчке, ты говоришь что: челы не знали что делать, но ты им принес "тайные знания", и они сразу проблему решили. DG>во второй сторочке, ты говоришь, что "тайных знаний" не бывает.
То что надо мерить — не тайные знания. Тем не менее не всем они известны.
DG>>>в данном случае, используется принцип инкапсуляции: строка рассматривается как черный ящик, и поведение строки фиксируется только на входе и выходе. с этой точки зрения, поведение внутри строки для наблюдателя неопределено. S>>Интересно, а для чего это не так?
DG>например, с точки зрения конкретного компилятора поведение внутри строки строго определенно, что куда и как преобразуется.
S>>Как может быть определена актуальность версии? Что из этого актуальнее, y1 или y2? S>>
S>>string y1 = y + "1";
S>>string y2 = y + "2";
S>>
DG>на основе лишь этого куска все следующие рассмотрения будут верными: DG>y, y1, y2 — три разных объекта DG>y, y1 — один объект, y2 — другой объект DG>y, y2 — один объект, y1 — другой объект DG>y, y1, y2 — один и тот же объект, y1 и y2 — две разные ссылки на один и тот же объект
Можно продолжить, что всевозможные строки это один объект, т.к. могут быть получены из пустой строки путем добавления значения, равного заданной строке.
S>>Я не даю определения тем вещам, которым они уже даны не мной.
DG>в мире для одного и того же слова, есть сотни, а то и тысячи определений с разным уровнем точности, соответственно как минимум ты обязан зафиксировать какое именно определение используешь и на каком уровне точности.
Тут разве не было ссылки на определение ООП идентичности ?
S>>Т.е. ты утверждаешь что у объектов y и (y + "1") same identity? Как ты отличишьь этот объект от (y + "2"), не зная, какая операция была выполнена вперед? S>>Если у тебя объект и версия имеют одну идентичность, то почему они различаются по значениям в один и тот же момент времени? Это противоречит определению идентичности.
DG>опять же как только выписываются все определения, то выясняется что никакого противоречия нет.
Никакого противоречия тому что всевозможные строки идентичны? DG>здесь есть две плоскости (две модели) — версионная и не версионная. DG>с точки зрения модели, которая не знает что такое версионность — функция идентичности считает объект одним и тем же, если совпадает идентичность объекта(из модели версионной) и версия объекта(из модели версионной), при этом эта модель считает две версии объекта совершенно разными объектами, которые никак между собой не связаны, что неудобно при рассмотрении многих сценариев.
Ты уже приводил определение идентичности версионной модели?
>> Если у тебя объект и версия имеют одну идентичность, то почему они различаются по значениям в один и тот же момент времени? DG>соответственно, с точки зрения неверсионной модели никакого противоречия нет, потому что объекты разные. DG>с точки зрения версионной модели противоречия тоже нет, потому что версионная модель допускает иметь одному и тому же объекту разные состояния для случая, когда это есть предыдущие состояния этого же объекта.
А ты можешь ответить на вопрос, является ли объект предыдущим состоянием некого объекта, или это самостоятельный объект?
DG>>>>>строка с одним и тем значением рассматривается как один и тот же объект S>>>>И это тоже определение? Чем строка отличается от например StringBuilder-а, что для нее особенное определение вводится? S>>Ты не объяснил обособленность строки в твоей системе определений
DG>потому что string использует immutable-версионность (а не backup-версионность), в отличии от stringbuilder-а
Это значит что никогда не ясно, является ли string объектом, или неактуальной версией какого-то объекта?
S>>У меня нет сомнений. Я вижу что твои определения и примеры несовместимы с традиционным ООП.
DG>опять религиозный догматический вывод. для полного образа тебе еще не хватает криков "сжечь еретика на костре!.
Почему догматический? Идентичность строк с одним значением + сохранение идентичности при операции "+" влечет идентичность всевозможных строк вне зависимости от их происхождения по твоим определениям. Очевидно, что это отличается от традиционного ООП, где две строки с разными значениями в некий момент времени являются различными объектами. Или проще, объект в ООП не может обладать двумя различными состояниями одновременно. Твои — могут обладать счетным числом состояний (без ограничений возможности платформы).
S>>>> Как быть с полиморфизмом?
DG>>>полиморфизм как был так и остается. и примере с null как раз применение полиморфизма и показывает. S>>identity является основой для работы полиморфизма. DG>>>или ты на самом деле не знаешь что такое полиморфизм? S>>Твой пример с null показывает что ты не знаешь что такое полиморфизм.
DG>одно из классических определений полиморфизма: DG>возможность работать одинаковым образом с разнородными объектами.
Это не лучшее определение лишь одной из частей полиморфизма.
DG>при этом реализация полиморфизма через vtable, это частный случай реализации полиморфизма.
Не реализации, а вообще, частный случай полиморфизма. Конкретно — subtype полиморфизма. Который есть подвид ad-hoc полиморфизма с разрешением конкретного поведения во время выполнения по первому аргументу. DG>например, в следующем коде полиморфизм есть — функция Main обрабатывает вывод разнородных объектов (строка, целое число, дробное число) одинаковым образом, но реализация полиморфизма сделана без vtable-а DG>
DG>void Main()
DG>{
DG> foreach (var x in new object[]{"Hello", "world", 37, 21.1})
DG>
Это параметрический полиморфизм
DG>для строго наличия наличия полиморфизма или отсутствия полиморфизма — необходимо сначала зафиксировать для какого кода по отношению к какому набору объектов делается утверждение. DG>следующий код полиморфен для всех объектов, которые реализуют IDisposable, и не полиморфен для набора объектов, которые реализуют IDisposable и не реализуют DG>
DG>var disposable = x as IDisposable;
DG>if (x != null)
DG> disposable.Dispose();
DG>
DG>null и полиформизм DG>следующий код не полиморфен для набора объектов: null и не null, и при наличии такого кода и делается утверждение, что null разрушает полиморфизм DG>
DG>if (point != null)
DG> point.Inverse();
DG>
null не является объектом
DG>в следующем примере Main полиморфно обрабатывает набор объектов: null и не null. DG>и null наоборот полиморфизм добавляет, а не разрушает. DG>
DG>void Main()
DG>{
DG> foreach (var p in new Point[]{new Point(x:1, y:2), null, new Point()})
DG>}
DG>
Ты смешал в одну кучу параметрический и специальный полиморфизм. в Main null обрабатывается как за счет параметрического, а в Inverce за счет обработки специального случая, но без полиморфизма. Таким образом, null тут таки ломает.
DG>>>ты все грозишься что всё можно, а сам еще даже ни одного вывода не сделал, ни строчки кода не привел... S>>Я сделал достаточно выводов относительно твоих определений. И строчки тоже приводил, даже не одну. S>>Добавь в свой первый вариант Distinct() и каждый объект будет меняться лишь однажды.
DG>согласен будет. только при этом код станет O(n*logn) вместо O(n) и концепция Нулевые побочные затраты, если не используется, пойдут к черту, а так все замечательно.
Могу подсказать решение за O(n) DG>это я намекаю на то, что определения подбираются такие, чтобы код был хорошим, а не наоборот — подбирается код (в том числе ужасный) под раз зафиксированные определения.
В этом и проблема, что ты подбираешь определения для того что бы сделать конкретную функцию удовлетворяющей спецификацию, причем рассчитываешь на то что тот кто использует твой код и его определения не совпадают с твоими, будет писать некие адаптеры с ненулевыми побочными затратами.
Понимаешь, не Inverse для списка точек решает какой быть точкой. Решение об иммутабельности точки должно приниматься на более высоком уровне архитектуре, чем подгонка определений для того что бы впихнуть реализацию функции инвертирования списка точек в спецификацию. Функция инвертирования списка точек должна работать с теми точками, с которыми умеет работать вся остальная программа.
Код пишется для того, что бы удовлетворить требованиям, а не требования для того что бы удовлетворить коду. Обычно.
Здравствуйте, DarkGray, Вы писали:
DG>достаточно ли только такой эквивалентности, чтобы сделать вывод корректно ли преобразование(при суперкомпиляции, рефакторинге и т.д.) из функции T F(T item) в метод class T{void F()}?
В общем случае — нет. Но, к счастью, никто такой задачи и не ставит. Суперкомпиляция, мифы про которую вы тут рассказываете, ничего подобного не делает. DG>вопрос всё тот же: DG>почему функцию Inverse корректно преобразовывать в метод Inverse
В общем случае — нет, некорректно. Вы же сами привели пример, где эти реализации не ведут себя одинаково. В конкретном коде это может оказаться корректным. То есть, к примеру, если вы выполнили в первом и втором случае все оптимизации компилятора — инлайнинг, распространение констант, алгебраические преобразования — и получился одинаковый целевой код, то да, преобразование было корректным.
DG>так же есть и вопрос и про обратное преобразование: DG>если код содержащий mutable-объект автоматически преобразовывается в код с immutable-объектом, то как меняется функция проверки, что объект тот же самый?
Ну, если у вас есть готовый автоматический преобразователь, то напустите его на код, использующий "функцию проверки". Он вам и выдаст результат.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, samius, Вы писали: S>По-моему не так давно вы согласились со мной что они все же не перестают быть объектами в смысле ООП. S>identity для них не отпадает. Просто она становится по силе эквивалентной эквивалентности. Но это не значит что она отпала.
Ок, сдаюсь-сдаюсь. S>>Простой пример на пальцах: S>>
S>>p1 = new Point(1.1);
S>>p2 = p1.Inverse(); // нет, p2 - это никоим образом не "та же самая" точка, что и p1. Рассуждения про "версионную identity" - это антинаучный бред.
S>>p3 = p2.Inverse(); // нет, p3 - это не та же самая точка, что и p2.
S>>
S>и не та же, что и p1 (при ссылочном типе точек). S>>Зато p1 эквивалентна p3 в том смысле, что их можно везде использовать взаимозаменяемо, и на все "сообщения" они будут реагировать строго одинаковым образом. S>На все сообщения — да, но сравнение ссылок даст их отличить. Соответственно, вся логика, которая может быть построена на сравнении ссылок, будет чувствительна.
Ну вот это как раз артефакт того, что мы хотим работать с ними, как с настоящими объектами. Ссылочная identity тут только вредит.
Именно поэтому я хотел её у них "отобрать" — иначе мы имеем возможность писать некорректный код, который выглядит как корректный.
S>>Этот код легко организовать на дотнете, использовав struct Point. Он не будет вести себя как объект, и попытки обмануть природу при помощи боксинга и referenceEquals не покажут ничего интересного. S>Со struct — да, будет не докопаться.
Ну то есть докопаться-то можно будет:
if (!object.ReferenceEquals(p1, p3))
Console.WriteLine("Gosh, identity got all screwed up!");
if (!object.ReferenceEquals(p1, p1))
Console.WriteLine("Gosh, this is even worse than I expected!");
Но ничего интересного в этом не будет.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Эта рекомендация — полный бред. Размер данных таблицы не играет никакой роли.
у вас не зафиксированы до конца термины, чтобы можно было делать такое сильное утверждение.
как минимум не зафиксировано: "о каких запросах вообще идет речь"?
также не зафиксировано как определена операция сравнения для множеств через операцию сравнения для элементов.
зы
например, если запрос можно выполнить на основе лишь некластерного индекса(в частности, например, запрос существования записи) без последующего обращения к кластерному индексу, то поиск по некластерному индексу будет быстрее, и эффект будет тем сильнее проявляться, чем шире таблица.
S>Так вот, истинность KI>NI не зависит от размера одной записи S. И от количества записей N она тоже не зависит.
как только ты от словоблудия перейдешь к написанию формулы кол-ва логических чтений для B-tree для тех или иных запросов, то сразу увидешь, что зависит.
а теперь сделай переход к вероятностям: вероятность того, что та или иная страница уже лежит в кэше, а также как будет выражено время выполнения запроса через вероятность нахождения тех или иных страниц в кэше.
зы
например, если ОП хватает, чтобы non-leaf pages в основном лежали в кэше (а так обычно и бывает), то производительность будет определяться в первую очередь как много надо прочитать leaf-pages, чтобы получить ответ.
соответственно, чем меньше записей лежит на одной leaf-pages, то тем больше надо прочитать страниц всего, а также тем выше вероятность нарваться на фрагментацию.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Порядок вычислений и порядок композиции не одно и то же. Композиция не коммутативна, но никто не говорит что функция справа должна быть вычислена раньше, чем функция слева оператора композиции.
V>Тем не менее, для коммутативных операций это так.
Тоже неверно. Представим коммутативную операцию a ~ b = b ~ a = 1. То есть всегда возвращающую одно значение. Для нее требуется вычислять аргументы? Вообще-то нет.
Представим другую, некоммутативную операцию, a | b = not a. Для вычисления требуется вычислять аргументы? Тоже нет.
Вообще если принять нормальный порядок вычислений, а не аппликативный, то порядок вычислений с порядком композиции почти никак не зависят друг от друга.
Так как нормальный порядок вычислений всегда дает результат если это возможно, то его можно принять за умолчание в любой выичслительной теории если явно не указано обратное.
И в РА кажись не предполагается энергичный порядок.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>Тем не менее, для коммутативных операций это так. G>>Тоже неверно. Представим коммутативную операцию a ~ b = b ~ a = 1. То есть всегда возвращающую одно значение. Для нее требуется вычислять аргументы? Вообще-то нет.
V>А как мы ее представим в SQL или РА?
Функция, которая всегда возвращает пустую реляцию.
G>>Представим другую, некоммутативную операцию, a | b = not a. Для вычисления требуется вычислять аргументы? Тоже нет.
V>Ну.. сочинять несуществующие алгебры можно хоть до посинения.
Тем не менее такое можно выразить в терминах РА.
V>В любом случае, коль семантика операции известна (ты же настаиваешь, что вычислять аргументы не надо, т.е. мы знаем об этом), кто мешает привести ее к правой (канонической) части, и затем отбросить все эти рассуждения за ненадобностью?
Так именно знание семантики позволяет проводить преобразования без вычисления. Ты же делаешь утверждения касающиеся всех коммутативных функций и говоришь что для них порядок вычислений связан с порядком композиции.
G>>Вообще если принять нормальный порядок вычислений, а не аппликативный, то порядок вычислений с порядком композиции почти никак не зависят друг от друга. V>Это для независимых аргументов так. Дык, случай независимых аргументов априори не может вызвать разногласий, тут спорить нечего.
Это для любых аргументов.
G>>Так как нормальный порядок вычислений всегда дает результат если это возможно, то его можно принять за умолчание в любой выичслительной теории если явно не указано обратное. G>>И в РА кажись не предполагается энергичный порядок.
V>Если у нас идут в выражении постоянные проекции и переименования, то даже для ленивого порядка вычислений необходимо будет сделать всю "линкову" всех проекций атрибутов и их переименований ДО начала вычислений, причем именно таким образом, как если бы эти значения распространялись в случае энергичного вычисления. Но и это не важно.
Именно это и важно, и в РА описано что и как можно переставлять и объединять. Ты же говоришь что это сделать нельзя для некоторого класса преобразований.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>>>Тем не менее, для коммутативных операций это так. G>>>>Тоже неверно. Представим коммутативную операцию a ~ b = b ~ a = 1. То есть всегда возвращающую одно значение. Для нее требуется вычислять аргументы? Вообще-то нет.
V>>>А как мы ее представим в SQL или РА? G>>Функция, которая всегда возвращает пустую реляцию.
V>Я таки настаиваю ее изобразить. Потому что если это именно ф-ия как "черный ящик", то аргументы будут для такой ф-ии вычислены, хоть и не будут использованы внутри самой ф-ии, а если не черный ящик, то таки хотелось посмотреть на примере SQL (откуда она пойдет в РА).
SQL, в отличие от РА предполагает аппликативный порядок вычислений. Найдешь реализацию SQL где это не так — спокойно сделаю.
G>>>>Представим другую, некоммутативную операцию, a | b = not a. Для вычисления требуется вычислять аргументы? Тоже нет.
V>>>Ну.. сочинять несуществующие алгебры можно хоть до посинения. G>>Тем не менее такое можно выразить в терминах РА. V>Нельзя.
Значит можно аналогичное. Сути не меняет.
V>>>В любом случае, коль семантика операции известна (ты же настаиваешь, что вычислять аргументы не надо, т.е. мы знаем об этом), кто мешает привести ее к правой (канонической) части, и затем отбросить все эти рассуждения за ненадобностью? G>>Так именно знание семантики позволяет проводить преобразования без вычисления. Ты же делаешь утверждения касающиеся всех коммутативных функций и говоришь что для них порядок вычислений связан с порядком композиции.
V>Речь о коммутативных операциях, а они даны были по ссылке. В остальном рассуждения такие же как для предыдущего примера, т.е. ты изобрел не операцию РА, а просто некую ф-ию и спекулируешь на порядке вычисления ее аргументов. Ты еще не забыл, ф-ии в РА применимы к каждому кортежу, а не ко всему отношению?
А что мешает такую функцию представить как функцию отношения? Например t — отношение, s — органичение, f — функция. если рассмотреть композицию s(f(t)), то она не равна f(s(t)), но ведь никто не мешает построить ограничение s' такое что s(f(t)) = f(s'(t)), причем при некоторых условиях на для f получится s семантически эквивалентно s'. Причем эти условия элементарно можно проверить.
При этом f(s'(t)) может вычисляться быстрее, чем s(f(t)). И конечно любой движок субд пытается по-максимуму такие преобразования делать. Конечно движок субд опирается на семантику того что происходит и некоммутативность некоторых операций в общем случае ему не помеха.
V>Да, именно. Утверждал что перестановку в общем случае проводить нельзя. Можно только для случаев, являющихся заведомо коммутативными.
См выше. Некоммутативность не помеха перестановке вычислений. А если рассмотреть более общую картину, где могут быть сайд-эффекты, то и коммутативность не всегда дает возможность вычисления переставить.
V>Для всех остальных это будут преобразования, с получением совсем других выражений, что совсем не есть тоже самое, что перестановка.
Это будет перестановка вычислений. Просто у тебя в мозгу засело что "порядок вычислений" == "порядок аргументов", что как раз не верно в большинстве случаев.
V>Это уже пошло жонглирование и уловки.
Это правда жизни. Большинство оптимизации так выполняется.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>>>А как мы ее представим в SQL или РА? G>>>>Функция, которая всегда возвращает пустую реляцию.
V>>>Я таки настаиваю ее изобразить. Потому что если это именно ф-ия как "черный ящик", то аргументы будут для такой ф-ии вычислены, хоть и не будут использованы внутри самой ф-ии, а если не черный ящик, то таки хотелось посмотреть на примере SQL (откуда она пойдет в РА). G>>SQL, в отличие от РА предполагает аппликативный порядок вычислений. Найдешь реализацию SQL где это не так — спокойно сделаю.
V>И где это ограничение явно указано?
В семантике функций.
V>Опять же, ты не забыл замечание про минимум 2 вида аналитических выражений в РА — это собственно выражения РА и выражения-ограничения в выборке или разновидностях соединений. Какой уровень ты имел ввиду?
А ты какие когда говорил про коммутативность?
G>>Значит можно аналогичное. Сути не меняет.
V>Меняет. Ты же походя присвоил коммутативность некоей произвольной ф-ии, показав затем, что она нихрена не коммутативна из своего определения. Меня это улыбнуло, понятное дело, просто любопытно таки докопаться до всей цепочки рассуждений, которое могло ТАКОЕ породить.
Я привел функцию, которая формальному определению коммутативности соответствует. У тебя какое-то другое определение?
V>>>Речь о коммутативных операциях, а они даны были по ссылке. В остальном рассуждения такие же как для предыдущего примера, т.е. ты изобрел не операцию РА, а просто некую ф-ию и спекулируешь на порядке вычисления ее аргументов. Ты еще не забыл, ф-ии в РА применимы к каждому кортежу, а не ко всему отношению? G>>А что мешает такую функцию представить как функцию отношения? Например t — отношение, s — органичение, f — функция. если рассмотреть композицию s(f(t)), то она не равна f(s(t)), но ведь никто не мешает построить ограничение s' такое что s(f(t)) = f(s'(t)), причем при некоторых условиях на для f получится s семантически эквивалентно s'. Причем эти условия элементарно можно проверить.
V>Мешает то, что ф-ии ограничения, где аргументами идут отношения — это уровень исчисления кортежей, но не уровень РА. Задача РА как раз преобразовать "структурные" формулы РИ в "плоские" операции РА, где ф-ии ограничения будут в терминах операций над атрибутами кортежей. Курить определение ограничения в РА.
То есть ты признаешь что далеко не любые коммутативные функции соответствуют тому что ты написал. Теперь давай выясним какие все таки соответствуют.
V>Попробуй кстате, "просто поменять вычисления местами" (С), мне любопытно. Замечания про ленивые vs энергичные я уже делал — ничего не меняется на уровне вычисления атрибутов кортежей.
G>>При этом f(s'(t)) может вычисляться быстрее, чем s(f(t)). И конечно любой движок субд пытается по-максимуму такие преобразования делать.
V>Я это понимаю, и даже давал больше по этой теме, но ты невнимательно читал. Да, именно, уровень РА нужен для того, чтобы в его терминах породить ВСЕВОЗМОЖНЫЕ решения исходной формулы, потому что коль на уровне РА отсутствуют ф-ии над отношениями, т.е. отстуствует вложенность в ограничениях, т.е. отсутствует рекурсия формул, становится возможным произвести оценку сложности операций. Так вот, там, где некий автоматический движок, перечисляющий всевозможные решения в терминах РА знает об декомпозиции исходной схемы на отношения, он может не просто породить s'(t), он может породить s'(t'), где t' — другое отношение, но сохраняющее зависимости исходной схемы. Прочувствовал разницу?
Совершенно не понял о чем ты. Я ведь говорю не только о некоторых преобразованиях в пределах одной операции, а в перестановке вычислений для композиции операций. И это при том что композиция в общем случае некоммутативна.
G>>Конечно движок субд опирается на семантику того что происходит и некоммутативность некоторых операций в общем случае ему не помеха.
V>Так вот, к большому пребольшому сожалению, движки СУБД не имеют понятия о семантике, т.к. обычно не реализовано одно из самых важных правил Кодда, позволяющее сохранять зависимости исходного прикладного отношения и проведенной конкретной декомпозиции. СУБД не делает никаких предположений относительно избыточности данных, принадлежащих одному домену и одному "логическому" атрибуту в рамках всей схемы.
Это тебя совсем не туда понесло.
V>>>Да, именно. Утверждал что перестановку в общем случае проводить нельзя. Можно только для случаев, являющихся заведомо коммутативными. G>>См выше. Некоммутативность не помеха перестановке вычислений. А если рассмотреть более общую картину, где могут быть сайд-эффекты, то и коммутативность не всегда дает возможность вычисления переставить.
V>Нету сайд-эффектов, а последовательность вычислений есть.
Она всегда есть, но она не совпадает с порядком записи аргументов и композиции функций.
V>Понимаешь... злобные функциональщики малость лукавят. Ф-ий подход зиждется на процедурном, а тот не отрицает зависимость результата от порядка вычисления. Просто коль отсутствуют побочные эффекты, то аргументы ф-ий можно вычислять в произвольном порядке. Но это малость не то же самое, что зависимые вычисления делать в произвольном порядке. А я на этой зависимости настаивал изначально, мне случай независимых аргументов неинтересен, на то они и независимые.
А что значит "зависимые вычисления" если у нас есть ленивость? А по сути ничего. Если итоговый результат не не нужен или нужен не полностью, то "зависимые вычисления" можно и не вычислять. И опять таки коммутативность тут никакой роли не играет.
DG>>>т.е. ты используешь эквивалентность понятий переменная и объект?, но при этом также утверждаешь, что переменная не является объектом? интересно живешь... S>>Я не использовал эквивалентность этих понятий, они и не эквивалентны. Я заменил локальную переменную полем объекта, ровно как и компилятор. Для этого не требуется эквивалентность переменной и объекта.
DG>ты использовал, что переменная эквивалентна полю объекта,
Чушь DG>а из это следует, что переменная эквивалентна объекту.
Чушь
Из того что ты увеличил косвенность не следует что понятия переменной и объекта эквивалентны. Тем более, что обратная замена не всегда возможна.
DG>или более формально, ты использовал, что: DG>1. объявление переменной типа T эквивалентно созданию объекта Переменная с полем T
нет. Сравни:
T x;
new Переменная();
DG>2. присвоение переменной эквивалентно присвоение полю DG>3. получение значения переменной эквивалентно получению значения поля
И это чушь. Я это не использовал. Что бы делать утверждения относительно кода с сахаром, нужно знать, во что он разворачивается. Я произвел соответствующее преобразование. Все. Никаких спекуляций об эквивалентности и идентичности.
DG>доказательство: DG>4. поле объекта эквивалентно свойству объекта без доп. поведения DG>5. свойство объекта эквивалентно двум методам GetValue/SetValue DG>6. (из 2, 4, 5) присвоение переменной эквилентно вызову метода SetValue DG>7. (из 3, 4, 5) получение значения переменной эквивалентно вызову метода GetValue
DG>из 1, 6, 7: DG>
DG>8. объявление переменной типа T эквивалентно созданию объекта Переменная<T>
DG>9. присвоение переменной эквивалентно вызову метода SetValue
DG>10. получение значения из переменной эквивалентно вызову метода GetValue
DG>
DG>чтд
ты доказал эквивалентность замены переменной не объектом. Ты доказал эквивалентность замены переменной типа T на переменную типа O, храняющу объект (ссылку на объект) типа O, содержащего методы, которые позволяют ... Ты даже не избавился о переменной, а говоришь об эквивалентности объекта и переменной. А раньше утвреждал что переменная объектом является.
З.ы. Способ размещения/хранения значения переменной в модели вычислений не имеет значения при условии что значение сохраняется между его сохранением и последующими чтениями. Пусть хоть лента Тьюринга на хомячковой тяге.
Здравствуйте, DarkGray, Вы писали:
DG>>>2. присвоение переменной эквивалентно присвоение полю DG>>>3. получение значения переменной эквивалентно получению значения поля S>>И это чушь. Я это не использовал. Что бы делать утверждения относительно кода с сахаром, нужно знать, во что он разворачивается. Я произвел соответствующее преобразование. Все. Никаких спекуляций об эквивалентности и идентичности.
DG>шаманизм в его ярком проявлении. DG>вместо того, чтобы рассуждать "челы из микрософт делают преобразование на основе таких-то и таких-то правил эквивалентности и поэтому оно есть правильное" ты рассуждаешь "так как это преобразование делают челы из микрософт значит оно есть правильное".
В рамках разговора о корректности программы, компилируемой компилятором микрософт, это единственно верное рассуждение.
DG>второй подход плох тем, что в твоей карте мира не остается возможности делать утверждения: преобразования компилятора правильные или нет и при каких условиях
Утверждения относительно правильности преобразований компилятора в контексте корректности программы, компилируемой этим компилятором неинтересны. Даже если бы компилятор микрософт делал все неправильно, имело бы смысл использовать именно его преобразования для того что бы делать утверждения относительно программы.
DG>в том-то и дело, что в данном случае замена переменной на объект делается на основе имеющейся эквивалентности переменной и поля объекта, и ничего нового придумано не было.
Кроме эквивалентности этих понятий.
DG>в c#-е переменная и поле того же типа полностью эквиваленты (за исключением времени жизни). и переменную можно считать частным случаем поля.
Так же полностью эквивалентны как совок и экскаватор. И экскаватор можно считать частным случаем совка.
DG>вот эквивалентность поля и простого свойства в .net-е страдает намного сильнее (мало того, что они не полиморфны с точки зрения реализации (хотя полиморфны с точки зрения поведения)), так есть еще такие операции как ref и out, которые поддерживают поля, но не поддерживают свойства. хотя эквивалентность поведения и здесь сохраняется, ref может быть заменен на два сообщения(две операции) get/set в виде двух делегатов или интерфейса с двумя методами, а out заменен на одно сообщение set (в виде интерфейса с одним методом или делегатом)
Извини, я не могу обсуждать здесь эквивалентность различных понятий. Разве что эквивалентную с точки зрения результата замену одного другим в одну сторону при некоторых условиях.
Но все-таки. Есть или нет такая эквивалентность — неважно при использовании конкретного компилятора. Он делает такую замену и не спрашивает тебя, считаешь ли ты ее корректной. Для корректности результата работы твоей программы имеет значение только факт такого преобразования. И уволь меня от рассуждений о корректности твоей программы согласно твоим понятиям об эквивалентности преобразований абстрактным компилятором.
Здравствуйте, DarkGray, Вы писали:
DG>>>и соответственно, не смотря на то, что функция чисто функциональная по определению — результат выражения зависит от истории применения orderby-ев к последовательности S>>А разве кто-то утверждал что результат применения чистых по определению функций не должен зависить от последовательности их применения?
DG>утверждается, что Referential transparency функцию можно заменить на ее результат. DG>order-by, меняющий одинаковые значения нельзя заменить на ее результат, потому что неизвестно как именно она меняет одинаковые параметры.
Ты подключаешь все новые термины и все время забываешь поглядеть в википедию. Для referential transparency не нужно знать какой будет результат. Для нее достаточно детерминированности функции. OrderBy детерминированна. И могла бы быть детерминированной, даже если бы не была stable (и не использовала бы rnd для принятия решений).
DG>например: DG>((key:2,value:1), (key:1, value:3), (key:1,value:2)).order-by(pair => pair.key) нельзя заменить на результат. DG>потому что непонятно на какой результат менять на:
Мне — понятно. http://en.wikipedia.org/wiki/Sorting_algorithm#Stability http://stackoverflow.com/questions/1209935/orderby-and-orderbydescending-are-stable
и даже msdn
This method performs a stable sort; that is, if the keys of two elements are equal, the order of the elements is preserved. In contrast, an unstable sort does not preserve the order of elements that have the same key.
DG>при этом пока всё данные явно известны на этапе компиляции, это не составляет серьезной проблемы: можно тупо на этапе компиляции вызвать order-by и подставить что она вернет. DG>проблемы начинаются, если на этапе компиляции данные известны лишь частично.
Опять выдумываешь. Referential transparency не требует того что бы данные были известны на этапе компиляции.
Здравствуйте, DarkGray, Вы писали:
S>>Это не так (см определение побочного эффекта).
DG>ты постоянно задачи подгоняешь под определения. хотя все наоборот — определения вводятся для того, чтобы решать задачи.
Определения вводятся для того, что бы подразумевать одно и тоже под теми же терминами. Ты используешь термины неведомым мне образом, твое их использование противоречит доступным мне определениям.
DG>Есть задача — уметь вызывать только те куски кода, которые нужны для получения результата. DG>Эта задача, в первую очередь, исследовалась в рамках ФЯ для простых данных, и были введены такие понятия как side-effect, referential-transparency и т.д., которые мешают или помогают решать исходную задачу.
DG>Но эта же задача возникает, как для сложных данных (например, частично-известных), так и для других парадигм (например, ООП) — при этом понятия side-effect, referential-transparency остаются по смыслу теми же самыми, плывут лишь детали.
Понятие side-effect-а безотносительно задачи я понимаю иначе, чем ты. Что такое сложные данные мне неизвестно. У тебя детали уплыли очень далеко.
DG>но об этом, к сожалению, букварей уже не издают.
Ты ведь где-то поднабрался истинного смысла? А все остальные юзают определения по-старинке, без конструктивизма. Займись изданием букваря, что-ли. Ну или дай свои определения тем терминам, что ты используешь. А те что в википедии — они не про то, о чем ты хочешь поведать.
Здравствуйте, DarkGray, Вы писали:
DG>деление на декларивный и императивный код появилось на заре становления программирования при решении задачи: может ли меняться код исполнения при той или иной записи программы? и в какой степени?
Сам придумал? Если нет — дай ссылку.
DG>пока не было оптимизирующих компиляторов деление было более-менее четкое: DG>пролог, sql — декларативные: исполнитель делает что хочет;
Т.е. ты признаешь что sql когда-то был декларативным... Хорошо.
DG>а асм, алгол, форт, паскаль, си — императивные: исполнитель делает то, что записано в коде, в том порядке в котором записано.
DG>как появились оптимизирующие компиляторы — императивные языки перестали быть четко императивными, в них появилась декларативность: исполнитель в большинстве случаев стал выполнять другой код и в другом порядке, чем записано. DG>дело дошло даже до того, что маш. код перестал быть чисто императивным: современный процессор его выполняет в другом порядке, и другим способом чем записано
DG>и наоборот, по мере стандартизации де факто реляционных баз — от большинства простого sql-кода стало ожидаться, как именно он будет исполняться (в каком порядке какие выборки будут делаться, какие индексы будут использоваться и т.д.) DG>и sql перестал был четко декларативным: от конкретной реализации СУБД (тем более конкретной версии) ожидается, что sql-запрос будет выполняться строго заданным способом, и никак иначе.
Покажи мне способ строго задания sql запроса!
DG>соответственно, сейчас дискуссия о том является ли конкретная запись декларативной или императивной — это дискуссия ни о чем: DG>сейчас многое зависит от исполнителя (мощности его анализатора кода и возможностей его выполнения) — и без фиксирования исполнителя нельзя утверждать — этот код декларативный или императивный. а если зафиксирован исполнитель, то прежде чем говорить чего больше: декларативности или императивности необходимо сначала зафиксировать метрику — в каких единицах и каким способом измеряется декларативность или императивность.
А ты можешь назвать хоть один не императивный исполнитель sql? Хотя бы тот, который якобы был на заре становления программирования, когда sql еще был (по твоем рассуждениям) декларативен? Или тот, который (по рассуждениям vdimas-а) нельзя было бы выполнить на машине Тьюринга?
DG>при этом можно говорить, что такая запись более декларативная/менее императивная без явной фиксации исполнителя, если при этом измеряется какую степень свободы для исполнения дает та или иная запись; или если сравнивается мощность анализатора исполнителя, чтобы исполнитель мог получить ту или иную свободу исполнения, для той или иной записи кода.
Напомни, каким образом исполнитель связан с определением декларативности, если ты в него заглядывал?
Если ты о какой-то своей декларативности (как и о чистоте, побочных эффектах и т.п.), то я умываю руки.
S>Этот код не является чисто функциональным, т.к. использует недетерминированные функции.
если уж делаешь какие-то утверждения, то делай это правильно и четко.
твоя проблема, что ты умудряешься даже для железобетонных определений делать ужасные формулировки своих утверждений.
точная формулировка: функция конструирующая тип C не является чисто функциональной, т.к. использует недетерминированную функцию new Random().
остальные функции являются чисто функциональными и детерминированными.
и соответственно, как только ты бы сделал правильное и четкое утверждение, то скорее всего до тебя бы дошло, что тебе показывают и тебя просят подумать про ту часть кода, которая состоит из чисто функциональных детерминированных функциях.
вторая проблема, что ты считаешь собеседников заведомо глупыми. и любую неточность в формулировках ты трактуешь в пользу глупости собеседника, вместо того, чтобы самостоятельно устранить неточность и ответить по существу. при этом ты бы чему-то научился (и это был бы конструктивный подход), а так ты лишь чешешь свое самолюбие.
DG>>>а раз нет алгоритма, то и не существует объективного способа утверждать данная конструкция декларативна или императивна. G>>Для конкретного языка вполне можно утверждать. Например для русского.
DG>приведи алгоритм, как для программы на русском языке измерить относится она к классу: декларативная или императивная?
Декларативная не содержит последовательности действия для завершения результата, а только описание самого результата.
G>>>>Программа в императивном стиле может быть исполнена самым тупым исполнителем, например процессором. DG>>>вот ты сейчас предлагаешь уже конструктивное определение для понятия "императивный стиль" (и кстати в этом утверждении уже появился конкретный исполнитель), которое уже как-то измеримо. G>>Исполнителя заметь ты выдумал. Хотя для любого ТЗ (алгоритма) есть исполнитель.
DG>одно с другими не стыкуется. двумя строчками выше в твоей фразе написано слово "исполнитель". оно туда случайно попало?
Это ты его написал
DG>>автомат из одной императивной команды:
DG>>установить положение стула не ближе 5 метров от дивана.
G>А толку?
при наличии исполнителя, который умеет выполнять эту команду — такого автомата достаточно.
DG>>>тогда появляется система утверждений: DG>>>у1. для всякой императивной программы известен алгоритм, который позволяет эту программу выполнить с помощью процессора x86 за предсказуемое время с потреблением предсказуемого кол-ва ресурсов. DG>>>у2. не для всякой декларативной программы известен алгоритм, который позволяет эту программу выполнить с помощью процессора (и далее по тексту) G>>Без рассмотрения языка смысла не имеет. Как выполнить императивный алгоритм на русском языке с помощью процессора x86? G>>1) Подойди к стулу G>>2) Подними стул G>>3) Если ты стоишь дальше 5 метров от дивана, то подойди к дивану, если ближе, то отойди. G>>4) Поставь стул
DG>например, взять алгоритм которые русские слова переводит в слова языка python.
И? От этого стул окажется на расстоянии 5 метров от дивана?
DG>Проблема может быть с понятиями (а не словами), вернее даже с распознаванием образов (как распознать, какой объект реального мира соответствует понятию "стул"?) — и соответственно всё упрется в исполнителя (умеет он или нет выделять объекты стул и диван из окружающего мира), при этом если утверждается, что умеет, потому что на каждый стул и диван приклеена бирка с поясняющим штрихкодом (или может речь вообще про растановку мебели внутри виртуальной комнаты), то эту программу осилит и процессов x86.
Напиши проще: понимает ли исполнитель язык. Я тебе об этом и толкую, что без языка нет смысла обсуждать. И совершенно необязательно это должен быть формальный язык или машинный язык.
DG>>>что даем нам индикатор: DG>>>у3. если для программы известен алгоритм, позволяющий выполнить ее с помощью процессора x86, то с большей вероятностью, она принадлежит к классу императивных программ. G>>Мощность языков программирования по тьюрингу одинакова и они все выполняются на x86 процессорах. Так что фраза твоя ни о чем.
DG>эта эквивалентность не обещает, что алгоритм после преобразования останется вычислимым за заданное время.
А причем тут время? Мы про время еще ничего не говорили. Не надо лишние, для понимания сути, вещи включать.
DG>например, склейка двух списков, которая для исполнителя с произвольным доступом к памяти занимает O(1), для исполнителя — чистое ФЯ без ленивости — O(N), для МТ-исполнителя — уже будет O(N^2).
Это свойство исполнителя, но причем тут декларативность\императивность? Они от исполнителя не зависят, они от языка зависят.
G>> Программа на C будет императивна, а на хаскеле декларативна, а обе считают числа фибоначчи. DG>какое это дает различие?
Различие в том что прогармма на C выглядит как последовательность шагов для вычисления нужного числа, программа на haskell больше похожа на математическое определение.
Естественно с точи зрения дальнейшего анализа и рассуждения над программой лучше иметь декларативный код, так как он ближе к ТЗ.
S>>Допускаю что ты под эквивалентностью подразумеваешь отношение эквивалентности, а не какую-то свою эквивалентность. Если какую-то свою, то все другие рассуждения неверны.
DG>языки A и B эквиваленты — если алгоритм записанный на языке А можно записать на языке B (и наоборот)
Совсем другая эквивалентность, чем та, которую ты определял через возможность реализовать МТ (и на МТ). Для того что бы языки были эквивалентны по такой эквивалентности, не нужно что бы даже один из них имел отношение к МТ.
Здравствуйте, samius, Вы писали:
S>Зачем тут исполнитель? Упорядоченность по ключу определяет остортированноую последовательность. Для однозначности можно потребовать устойчивость. Какая разница, какой исполнитель сортировал?
Более того, упорядоченность по ключу задаётся выполнением предиката (i<j) ==> (item[i].Key <= item[j].Key)
При этом нам необязательно предоставлять конкретный алгоритм проверки этого предиката.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали: DG>при этом используется, что в реальных программах необходима однозначность значимой части результата, и что одновременно две функции F не исполняются
Вторая часть предположения
а) слишком сильная, т.е. не основана ни на чём, кроме веры
б) недостаточно сильная, т.к. даже без "одновременного исполнения" двух функций F мы можем получить спецэффекты, которые вашей программой не предусмотрены.
Вот такого примера достаточно:
int HellSum(IEnumerable<int> source)
{
var s = 0;
foreach(var i in F(source))
{
s+= i;
_a = 0;
}
}
IEnumerable<int> F(IEnumerable<int> source)
{
foreach(var i in source)
{
_a = i ^ (i << (_a &&0x4)) ^ (i >> 16));
yield return i ^ _a;
}
}
private int _a = 42;
DG>декларация же может быть задана в виде: результат должен быть таким же, как результат вот такого-то вычисления, а выполнять можете как хотите (и для сложных алгоритмов нет другого способа задания результата)
Как интересно. То есть вы настаиваете, что разницы между декларативным и императивным описаниями нет. Тогда объясните это vdimas-у, а то он почему-то считает РА более императивной, чем РИ.
DG>при этом утверждение "делайте как хотите, главное чтобы результат был тем же самым" и так уже говорится, что для ФЯ, что для ООП и т.д. — что внутреннее поведение неважно, важно чтобы сохранялось внешнее поведение(внешний результат)
Вы движетесь в правильную сторону. Остаётся понять, что такое "внешнее поведение", и вы сможете отличить декларативную программу от императивной.
DG>что две спецификации результата, отличающиеся лишь спецификацией результата для некорректного поведения — для значимой части программ являются одной и той же спецификацией.
Отлично. Осталось определить, что такое "корректное поведение", что такое "некорректное поведение", и что такое "результат". А то вот вы взяли и "исправили" мою программу, написав свою. Да, "результат" работы вашей программы иногда получается таким же, как и у моей программы.
Но ведь тогда я могу в некоторой библиотеке заменить вычисление синуса на return 0; сказав, что во всех корректных программах аргумент всегда равен нулю, а те, кто передаёт не ноль — сами виноваты. Чем моя аргументация будет хуже вашей? Она столь же произвольна.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>>так как говоришь в математике называется множество с заданной функцией перебора элементов? S>>Если ты о последовательности, то она не является множеством.
DG>а где ты говоришь учился на математика?
УрГУ
DG>
DG>Последовательность — это набор элементов некоторого множества:
DG> для каждого натурального числа можно указать элемент данного множества;
DG> это число является номером элемента и обозначает позицию данного элемента в последовательности;
DG> для любого элемента (члена) последовательности можно указать следующий за ним элемент последовательности.
a sequence is an ordered list of objects (or events)
Твой трюк с подменой текста в википедии пошловат.
S>> Потому затрудняюсь ответить, как называется такая пара, особенно безотносительно свойств этой пары. S>>Лучше прочитай определение последовательности.
DG>хуже невежд только невежественные фанатики, которые считают, что то, что они знают — является полным и окончательным знанием (в частности, считающие — что они-то уж знают, что такое правильное определение терминов)
Еще хуже — тыкать в определение, и не понимать что там написано, или подменять текст в нем.
DG>ps DG>формальное определение последовательности — это произвольное множество отображенное на множество натуральных чисел.
Произвольное множество, отображенное на множество натуральных чисел, в общем случае не является множеством.
Вот тебе тривиальный пример { 1, 1, 1, 1, ... }
DG>ззы S>>Если ты о последовательности, то она не является множеством.
DG>в последней версии математики вообще ничего кроме множеств нет, даже числа и то вводятся, как множества.
Выше пример не множества.
S> отображение множества натуральных чисел на наше произвольное множество
из одного следует другое. можно лишь поговорить на тему: скольки элементам одного множества сколько элементов другого множества соответствует.
S>Что характерно, никакой "функции перебора" ни в том, ни в другом случае нет
если есть отображение множества на множество натуральных чисел, при этом одно натуральное число переходит в один элемент множества, то есть и функция перебора. перебирая натуральные числа перебираются и элементы исходного множества.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
DG>>>ps DG>>>формальное определение последовательности — это произвольное множество отображенное на множество натуральных чисел. S>>Произвольное множество, отображенное на множество натуральных чисел, в общем случае не является множеством. S>>Вот тебе тривиальный пример { 1, 1, 1, 1, ... }
S>Вы слишком строги с коллегой DG. Он, конечно же, имел в виду отображение множества натуральных чисел на наше произвольное множество, а не наоборот.
Вау, я был слишком добр к нему. Я не заметил, что он написал отображение НА множество натуральных чисел, и считал что он написал отображение множества натуральных чисел.
Пример, кстати, показывает отображение множества натуральных чисел на множество натуральных чисел, заданное в виде
f(n) = 1
S>Хотя задать последовательность, конечно же, можно и без прямого указания этого отображения. А, например, при помощи задания на элементах множества отношения полного порядка. Из этого отношения можно восстановить отображение натуральных чисел в элементы множества.
Это тот случай, когда множество элементов последовательности будет совпадать с множеством элементов множества. Но наличие порядка будет отличать последовательность от множества.
S>Что характерно, никакой "функции перебора" ни в том, ни в другом случае нет, несмотря на трогательные заблуждения нашего оппонента. Если у нас есть отображение множества натуральных чисел на множество наших элементов, M: x:N->s:S, то нам ничего перебирать не нужно. Можно просто получить s42 = M(42).
S>Задание "функции перебора" — это третий способ математически определить последовательность, задав функцию Succ: s1:S -> s2:S.
Да, как способ годится, но он не такой гибкий, как отображение. В виде функции Succ мы не сможем задать последовательности вида { 1, 1, 1, 2, 2, 2, ... }
S>Вы слишком строги с коллегой DG. Он, конечно же, имел в виду отображение множества натуральных чисел на наше произвольное множество, а не наоборот.
я имел ввиду именно отображение множества на натуральные числа, потому что только в этом случае при переборе по натуральным числам и появляется фальсифицируемость такого отображения, которая и проявится для случая, если мы отобразили два различных элемента множества на одно и то же натуральное число.
если мы отображаем натуральные числа на множество и потом по натуральным числам множество и перебираем, то такое отображение не фальсифицируемо (и мы никогда не узнаем, что какие-то исходные элементы множества не перебираются)
S>2. Ты вообще мои ответы читаешь перед тем как скипаешь неудобные тебе вещи? Еще раз. S>Функцией F'::X->Nat невозможно задать последовательность с повторяющимися элементами. Прежде чем скипать, попытайся поразмыслить над этим.
следующий вариант задает отображение с повторяющимися элементами
F'(false) -> i, where 0<=i<=2
F'(true) -> i, where 3 <= i < = 5
DG>некорректная, если строго требуется однозначная последовательность
Ну, то есть никакой последовательности не задаётся. Если вы, конечно, не хотите придумать какую-то свою трактовку термина "последовательность", которая несовместима ни с одной из общепринятых трактовок. Вот, например, из википедии: всякое отображение f: N -> X множества натуральных чисел N в заданное множество X называется последовательностью.
Вместо того, чтобы принять это определение и двигаться дальше, вы занимаетесь ерундой.
То, что вы пытаетесь назвать "последовательностью", математики называют "линейно упорядоченное множество со строгим порядком". Вот как раз в нём участвуют все элементы, и каждому можно сопоставить уникальное натуральное число.
Определение этого множества, которое вы пытаетесь в муках родить, выглядит совсем не так. Подсмотрите в википедии.
DG>я утверждал, что функции перебора достаточно, чтобы множество являлось последовательностью, и не утверждал, что это необходимо. слово "именно" является аналогом слова "необходимо", а не слова "достаточно".
Все ходы записаны.
Вы утверждали
, что последовательность — это множество с заданной функцией перебора.
Впрочем, вы противоречите сами себе — как бы вы ни задавали функцию перебора — опосредованно, как F:N->X или как Succ: X->X, всё равно вы не получите желаемого результата: трудовато сформулировать условие "функция должна покрыть всё множество X".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Боюсь вас разочаровать, но это происходит исключительно в вашей голове. В головах остальных людей голоса дают такое определение отображения:
Функция f (отображение, операция, оператор) — это закон или правило, согласно которому каждому элементу x из множества X ставится в соответствие единственный элемент y из множества Y.
При этом говорят, что функция f задана на множестве X, или что f отображает X в Y.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Впрочем, вы противоречите сами себе — как бы вы ни задавали функцию перебора — опосредованно, как F:N->X или как Succ: X->X, всё равно вы не получите желаемого результата: трудовато сформулировать условие "функция должна покрыть всё множество X".
вопрос же не в том, как это сформулировать, а как это можно использовать для реального мира, в котором кол-во шагов применимых алгоритмов можно ограничить наперед заданным числом N.
S> В головах остальных людей голоса дают такое определение отображения
Функция f (отображение, операция, оператор) — это закон или правило, согласно которому каждому элементу x из множества X ставится в соответствие единственный элемент y из множества Y.
допустим, что отображение и функция — это одно и тоже.
тогда это определение противоречит определению многозначного отображения
Многозначное отображение — разновидность математического понятия отображения (функции).
S>И последовательность, определенная многозначным отображением есть последовательность подмножеств, которая записывается, например следующим образом:
это странный вывод.
многозначное отображение X->Nat есть обычное отображение, которое можно отразить и получить Nat->X (при этом если X->Nat было right-unique, то Nat->X будет left-unique), то это даст последовательность. Свойство, чтобы в Nat не было дырок желательно, но не является необходимым. Nat с "дырками" можно еще раз отобразить уже в Nat без "дырок".
с точки зрения математики здесь всё корректно, а вот с точки зрения реальных алгоритмов уже не всегда ("затягивание" дырок может выйти за допустимое кол-во шагов)
S>А вы зачем-то вместо определения отображения приводите определение отношения.
согласен был не прав, использовал слово "отображение" вместо термина "отношение".
значит во всем что было написано до этого, вместо слова "отображение" читать "отношение".
Здравствуйте, DarkGray, Вы писали:
S>>Ок, вот мы задали некоторое отношение R в (X x N). Как нам из этого отношения получить последовательность?
DG>потребовать right-unique. DG>также необходимо, чтобы отношение было полным справа на всем множестве Nat(для бесконечных последовательностей) или на интервале (1..L), если это конечная последовательность.
Ну вот видите, как сложно. В то время как классическое определение не нуждается во всех этих уточнениях. Вопрос: зачем так извращаться, когда можно просто взять готовое определение и пользоваться им?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали: DG>какое готовое? http://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D1%81%D0%BB%D0%B5%D0%B4%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D1%81%D1%82%D1%8C
Читать раздел "определение". DG>и как его использовать для моего утверждения, что если хочется записать сложную последовательность из всех элементов множества X в декларации программы, то: DG>лучше использовать F(X)->N (требование left-unique при этом автоматически подразумевается) для однозначных последовательностей (или F(X)->set<N> для последовательностей, где одни и те же элементы используются несколько раз) и использовать автоматическое восстановление F(N)->X из F(X)->N, DG>вместо того, чтобы задавать F(N)->X, а потом пытаться доказать, что эта функция полная справа.
А его не надо использовать для вашего утверждения. Ваше утверждение изоморфно "для заворачивания шурупов лучше использовать плоскогубцы, чем молоток", и само по себе никуда не годится.
Вот вам другое утверждение: "если хочется записать сложную последовательность из всех элементов множества X без повторений в декларации программы, то лучше задать на этом множестве отношение строгого полного порядка, чем любые приседания с многозначными отображениями".
Для всех воображаемых вами конструкций математики придумали удобные определения и формулировки.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
В статьях про "Immutable object" или про "Неизменяемый объект" в Википедии, во всех примерах речь идет о типах, все экземпляры которых неизменяемы, хотя согласно определениям данным в начале статей i в примере ниже является неизменяемым объектом:
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Immutable object здесь 123.
I>Вот хрен, 123 здесь integer literal (значением которого инициализируется объект именуемый i).
integer literal это понятие во-первых из конкретного языка, во-вторых понятие времени разбора грамматики. в рантайме нет такого "integer literal". И в терминах OOP тоже нет такого понятия.
И i — это не имя объекта. Это его идентификатор в терминах OOP.
I>На неважно, главно, что ты увидел определение неизменяемого объекта здесь:
I>
Здравствуйте, samius, Вы писали:
S>integer literal это понятие во-первых из конкретного языка, во-вторых понятие времени разбора грамматики. в рантайме нет такого "integer literal". И в терминах OOP тоже нет такого понятия.
Во первых пример-то и был на конкретном языке, а не на ООПе; во-вторых "в рантайме" никакого 123 и нет, а есть объект инициализированный значением этого литерала.
S>И i — это не имя объекта. Это его идентификатор в терминах OOP.
А употребленное тобой "имя переменной" это в терминах чего было?
Здравствуйте, Lloyd, Вы писали:
L>Да, тип Int32 — неизменяемый. Отсутствие/наличие const тут погоды не делает, т.к. этот модификатор относится не к типу, а к переменной.
К объекту то есть (по крайней мере в C или C++, на котором пример, i является объектом). И вот определение из Википедии:
an immutable object is an object whose state cannot be modified after it is created
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>integer literal это понятие во-первых из конкретного языка, во-вторых понятие времени разбора грамматики. в рантайме нет такого "integer literal". И в терминах OOP тоже нет такого понятия.
I>Во первых пример-то и был на конкретном языке, а не на ООПе; во-вторых "в рантайме" никакого 123 и нет, а есть объект инициализированный значением этого литерала.
А в конкретном языке есть понятие "Immutable object"? Можно ссылку на упоминание его в спецификации?
Хорошо, пусть будет объект, инициализированный значением этого литерала. Но i — это не объект. Это идентификатор.
S>>И i — это не имя объекта. Это его идентификатор в терминах OOP.
I>А употребленное тобой "имя переменной" это в терминах чего было?
Хорошо, пусть будет "идентификатор".
Здравствуйте, igna, Вы писали:
L>>Да, тип Int32 — неизменяемый. Отсутствие/наличие const тут погоды не делает, т.к. этот модификатор относится не к типу, а к переменной.
I>К объекту то есть (по крайней мере в C или C++, на котором пример, i является объектом).
Нет, именно к переменной.
I>И вот определение из Википедии:
I>
I>an immutable object is an object whose state cannot be modified after it is created
Объектом тут является значение 123, и да, оно неизменяемое.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Lloyd, Вы писали:
L>>Да, тип Int32 — неизменяемый. Отсутствие/наличие const тут погоды не делает, т.к. этот модификатор относится не к типу, а к переменной.
I>К объекту то есть (по крайней мере в C или C++, на котором пример, i является объектом). И вот определение из Википедии:
I>
I>an immutable object is an object whose state cannot be modified after it is created
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Идентификатор i никак не является объектом.
I>Вот прям никак. А samius чем является, человеком или его псевдонимом на rsdn.ru?
Формально, samius это вывеска, под которой на rsdn пишет человек (я). И она не иммутабельна. Под ней технически может писать другой человек.
То что кто-то с samius-ом ассоциирует человека — это какая-то ошибка. То же касается почтовых адресов, учетных записей ICQ, и даже СНИЛС.
I>Тут произведена подмена понятия "называющий" на "указывающий".
Это не подмена, это аналогия.
I>Кроме того, обрати внимание, что "Луна" в твоем предложении все-таки небесное тело, а не его имя, покольку палец твой все-таки не на имя указывает.
Да, именно это там и написано.
I>То есть демагогия эта твоя цитата.
Здравствуйте, Lloyd, Вы писали:
L>Это не подмена, это аналогия.
Ложная. Указатель, хоть в программировании, хоть дорожный никогда не имеет значения того, на что он указывает. А что означает имя, само себя или то, что оно именует, зависит от контекста.
L>Да, именно это там и написано.
Ты все-каки задумайся над тем, что ратуя за строгое различение между именем и тем, что оно именует, ты сам употребил имя Луна во втором значении, а не написал чего-либо вроде:
Палец указывающий на то, имя чего Луна, не есть то, имя чего Луна.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, DorfDepp, Вы писали:
DD>>Если его положить в обертку, т.е., внутрь класса, тогда он превратится в "Immutable object".
I>Кто "он", объект именуемый i со значением 123, или объект класса-обертки?
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, samius, Вы писали:
I>>>Хорошо, формальная вывеска, ответь пожалуйста, какие из нижеприведенных идентификаторов i1, j1, i2 и j2 являются идентификаторами неизменяемых объектов? S>>Все являются.
L>Идентификатор все-таки не у объекта, а у переменной.
Верно. Но язык не допускает засовываение в i1, j1, i2, j2 изменяемых объектов.
И все-таки в ООП нет понятия переменной. Но есть идентификаторы объектов, ссылки на объекты. Как идентификаторы объектов i1-j2 все идентифицируют незименяемые объекты, даже если переменные изменяемы.
Здравствуйте, samius, Вы писали:
S>И все-таки в ООП нет понятия переменной. Но есть идентификаторы объектов, ссылки на объекты. Как идентификаторы объектов i1-j2 все идентифицируют незименяемые объекты, даже если переменные изменяемы.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>И все-таки в ООП нет понятия переменной. Но есть идентификаторы объектов, ссылки на объекты. Как идентификаторы объектов i1-j2 все идентифицируют незименяемые объекты, даже если переменные изменяемы.
I>И после выполнения присваивания
I>
I>i1 = 456;
I>
I>i1 начинает идентифицировать другой объект?
В терминах ООП — да. В терминах конкретного языка — i1 продолжит идентифицировать переменную, в которую положат новый объект.
Здравствуйте, samius, Вы писали:
S>В терминах ООП — да. В терминах конкретного языка — i1 продолжит идентифицировать переменную, в которую положат новый объект.
Что такое "положить объект в переменную", чем это отличается от "присвоить объект переменной"?
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>В терминах ООП — да. В терминах конкретного языка — i1 продолжит идентифицировать переменную, в которую положат новый объект.
I>Что такое "положить объект в переменную"
Это такая историческая глупость. Предки называли переменные rabyach1, rabyach2, что означало "рабочая ячейка". В эти ячейки "клали" значения. Но да, я подразумевал присваивание переменной значения.
I>чем это отличается от "присвоить объект переменной"?
Практически ничем. Оба выражения годятся для местечкового употребления, но верным все-таки будет являться "присваивание значения переменной". Хотя надо понимать, что за этим процессом может стоять вызов оператора присваивания/конструктора копирования, которые ничего о переменных не знают. Но в результате переменная получит новое значение.
Значения, точнее типы значений, могут быть иммутабельны сами по себе, а переменные сами по себе. И для того что бы отличать, что мы конкретно делаем, кладем в изменяемую переменную значение неизменяемого типа, или в неизменяемую переменную значение изменяемого типа, принято расставлять акценты об иммутабельности объекта/переменной.
Есть еще тонкость. Иммутабельность объекта определяется не его состоянием, а его наблюдаемым поведением. Например, следующий объект иммутабелен:
class Immutable
{
int v_;
public:
void Update() { v_++; }
};
Здравствуйте, samius, Вы писали:
S>Это такая историческая глупость. Предки называли переменные rabyach1, rabyach2, что означало "рабочая ячейка". В эти ячейки "клали" значения. Но да, я подразумевал присваивание переменной значения.
Ну то-то. А то начал с того, чем отличается переменная от ее имени, а кончил тем, что не удержал заданный самим собой уровень точности и формальности, и "наклал".
S>Практически ничем. Оба выражения годятся для местечкового употребления, но верным все-таки будет являться "присваивание значения переменной".
Ну слава богу! Так давай так и писать, а то я уж пытаюся приспособиться к твоему местечковому диалекту, и вот глагол заменил, а существительное оставил как в оригинале.
И кстати, в результате мы остались с переменными и значениями, куда вообще объекты-то делись, остались в местечковом диалекте? Может они и вовсе не нужны, достаточно переменных (и их имен, да ).
S>Значения, точнее типы значений, могут быть иммутабельны сами по себе, а переменные сами по себе. И для того что бы отличать, что мы конкретно делаем, кладем в изменяемую переменную значение неизменяемого типа, или в неизменяемую переменную значение изменяемого типа, принято расставлять акценты об иммутабельности объекта/переменной.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Это такая историческая глупость. Предки называли переменные rabyach1, rabyach2, что означало "рабочая ячейка". В эти ячейки "клали" значения. Но да, я подразумевал присваивание переменной значения.
I>Ну то-то. А то начал с того, чем отличается переменная от ее имени, а кончил тем, что не удержал заданный самим собой уровень точности и формальности, и "наклал".
не чем отличается переменная от имени, а с того, что имя переменной это одно, а объект — другое.
S>>Практически ничем. Оба выражения годятся для местечкового употребления, но верным все-таки будет являться "присваивание значения переменной".
I>Ну слава богу! Так давай так и писать, а то я уж пытаюся приспособиться к твоему местечковому диалекту, и вот глагол заменил, а существительное оставил как в оригинале.
давай
I>И кстати, в результате мы остались с переменными и значениями, куда вообще объекты-то делись, остались в местечковом диалекте? Может они и вовсе не нужны, достаточно переменных (и их имен, да ).
значение может быть полноценным объектом.
S>>Значения, точнее типы значений, могут быть иммутабельны сами по себе, а переменные сами по себе. И для того что бы отличать, что мы конкретно делаем, кладем в изменяемую переменную значение неизменяемого типа, или в неизменяемую переменную значение изменяемого типа, принято расставлять акценты об иммутабельности объекта/переменной.
I>Все-таки ты опять "наклал".
Вижу, тебя это интересует куда больше, чем тема, которую ты поднял.
Здравствуйте, samius, Вы писали:
S>не чем отличается переменная от имени, а с того, что имя переменной это одно, а объект — другое.
Так у нас все же три сущности: переменная, имя переменной и объект, или только две из них?
S>значение может быть полноценным объектом.
А в каком случае значение не является полноценным объектом?
Кроме того, в чем отличие между полноценным объектом и объектом, не являющимся полноценным, и всегда ли значение является объектом (не обязательно полноценным)?
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>не чем отличается переменная от имени, а с того, что имя переменной это одно, а объект — другое.
I>Так у нас все же три сущности: переменная, имя переменной и объект, или только две из них?
Это смотря в каком аспекте смотреть. А то еще и literal-ы могут затесаться. Так, ООП не знает что такое переменная и ее имя, и оперирует идентификаторами/ссылками. А ЯП может не знать, что такое объект.
S>>значение может быть полноценным объектом.
I>А в каком случае значение не является полноценным объектом?
См ниже
I>Кроме того, в чем отличие между полноценным объектом и объектом, не являющимся полноценным, и всегда ли значение является объектом (не обязательно полноценным)?
Что бы был объект, необходимы возможности отправки ему сообщений и object identity, которая представлена идентификаторами/ссылками. Если значению невозможно отправить сообщение, то нет смысла о нем говорить как об объекте.
Но т.к. типично значения используются лишь в контексте того что identity у них имеется (идентификатор, ссылка, алиас, или нечто, позволяющее обращаться к результату выражения), то о необходимости identity забывается и рассматривается лишь тип значения. И тогда если тип значения не допускает отправку ему сообщений, то смысла нет считать значения таких типов объектами.
Далее все зависит от соглашения конкретной ОО системы, что именно считать за посылку сообщения. Вообще говоря не обязательно считать методы экземпляра типа значения за сообщения. Так в выражении CloseHandle(hObject) можно считать что объекту по ссылке hObject передается сообщение "CloseHandle".
Здравствуйте, samius, Вы писали:
S>Это смотря в каком аспекте смотреть. А то еще и literal-ы могут затесаться. Так, ООП не знает что такое переменная и ее имя, и оперирует идентификаторами/ссылками. А ЯП может не знать, что такое объект.
В том аспекте, в котором было твое "имя переменной это одно, а объект — другое", имеются еще и переменные кроме имен переменных и объектов?
> Есть еще тонкость. Иммутабельность объекта определяется не его состоянием, а его наблюдаемым поведением. Например, следующий объект иммутабелен: >
> class Immutable
> {
> int v_;
> public:
> void Update() { v_++; }
> };
>
>
Ссылочку-обоснование можно? Потому как в данном случае меняется внутреннее состояние объекта. Как бы получается противоречие определениям. Два немутабельных объекта становятся неидентичными и объекты не могут быть расположены в ридонли.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Это смотря в каком аспекте смотреть. А то еще и literal-ы могут затесаться. Так, ООП не знает что такое переменная и ее имя, и оперирует идентификаторами/ссылками. А ЯП может не знать, что такое объект.
I>В том аспекте, в котором было твое "имя переменной это одно, а объект — другое", имеются еще и переменные кроме имен переменных и объектов?
В том аспекте — имеются.
Здравствуйте, grosborn, Вы писали:
>> Есть еще тонкость. Иммутабельность объекта определяется не его состоянием, а его наблюдаемым поведением. Например, следующий объект иммутабелен: >>
>> class Immutable
>> {
>> int v_;
>> public:
>> void Update() { v_++; }
>> };
>>
In some cases, an object is considered immutable even if some internally used attributes change but the object's state appears to be unchanging from an external point of view. For example, an object that uses memoization to cache the results of expensive computations could still be considered an immutable object.
Написано "In some cases", но вообще говоря именно такие объекты лежат в основе ленивых вычислений во многих чистых ФП языках.
G>Потому как в данном случае меняется внутреннее состояние объекта.
Не имеет значения, если внутреннее состояние не может влиять на наблюдаемое поведение.
G>Как бы получается противоречие определениям.
Каким именно? G>Два немутабельных объекта становятся неидентичными и объекты не могут быть расположены в ридонли.
Идентичность в ООП говорит о том, какие объекты считать идентичными, а какие — нет. В частности, идентичность, основанная на location объекта говорит что два объекта идентичны <=> они расположены в том же самом месте.
А причем тут ридонли — вообще непонятно.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>В том аспекте — имеются.
I>И чем переменные отличаются от объектов с одной стороны, и от имен переменных с другой?
Может ты таки откроешь какой-нибудь букварь и почитаешь? По-моему ты меня просто подтролливаешь. Уж не найти отличий переменной от объекта
Здравствуйте, samius, Вы писали:
S>Может ты таки откроешь какой-нибудь букварь и почитаешь? По-моему ты меня просто подтролливаешь. Уж не найти отличий переменной от объекта
Найти запросто, но тогда не понимаю, где ты видишь отличие переменной от ее имени. То есть на мой взгляд либо:
Не катит
> Не имеет значения, если внутреннее состояние не может влиять на наблюдаемое поведение.
Ха-ха-ха
Внутреннее состояние для того и состояние, что изменяет поведение.
Не изменяет только в твоем абстрактном примере, а так всегда изменяет.
> G>Два немутабельных объекта становятся неидентичными и объекты не могут быть расположены в ридонли. > Идентичность в ООП говорит о том, какие объекты считать идентичными, а какие — нет. В частности, идентичность, основанная на location объекта говорит что два объекта идентичны <=> они расположены в том же самом месте.
Поскольку внутреннее состояние всегда изменяет поведение, то объекты с изменяющимися внутренними состояниями нельзя считать немутабельными.
В общем с твоим определением возникают разночтения немутабельности из за разночтения идентичности. Идентичность определяется программистом, он решает какие объекты считать идентичными, от этого и в немутабельности путаница. Такие определения лучше не вводить лишний раз.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Может ты таки откроешь какой-нибудь букварь и почитаешь? По-моему ты меня просто подтролливаешь. Уж не найти отличий переменной от объекта
I>Найти запросто, но тогда не понимаю, где ты видишь отличие переменной от ее имени. То есть на мой взгляд либо:
I>(имя переменной == переменная) && (переменная != объект)
I>либо:
I>(имя переменной != переменная) && (переменная == объект)
на мой взгляд ни то ни другое. Про неравенство имени и именуемого объекта ты спорил уже с Lloyd-ом. А то что переменная не есть объект, видно хотя бы из времени жизни того и другого.
Здравствуйте, grosborn, Вы писали:
>> G>Ссылочку-обоснование можно? >> http://en.wikipedia.org/wiki/Immutable_object
G>Не катит
>> Не имеет значения, если внутреннее состояние не может влиять на наблюдаемое поведение.
G>Ха-ха-ха G>Внутреннее состояние для того и состояние, что изменяет поведение. G>Не изменяет только в твоем абстрактном примере, а так всегда изменяет.
выделенное слишком сильное утверждение. мой пример, конечно, абстрактный. Но пример с ленивыми вычислениями/мемоизацией — вполне рабочий.
>> G>Два немутабельных объекта становятся неидентичными и объекты не могут быть расположены в ридонли. >> Идентичность в ООП говорит о том, какие объекты считать идентичными, а какие — нет. В частности, идентичность, основанная на location объекта говорит что два объекта идентичны <=> они расположены в том же самом месте.
G>Поскольку внутреннее состояние всегда изменяет поведение, то объекты с изменяющимися внутренними состояниями нельзя считать немутабельными.
Посыл неверный, вывод тоже.
G>В общем с твоим определением возникают разночтения немутабельности из за разночтения идентичности. Идентичность определяется программистом, он решает какие объекты считать идентичными, от этого и в немутабельности путаница.
Ты не путаешь идентичность (identity) с равенством (equality)? G>Такие определения лучше не вводить лишний раз.
Я ничего нового не вводил в этой теме. Идентичность, основанная на location, придумана не мной.
Здравствуйте, samius, Вы писали:
S>на мой взгляд ни то ни другое. Про неравенство имени и именуемого объекта ты спорил уже с Lloyd-ом.
Ты передернул, я же написал "имя переменной == переменная", объекта там не было.
Кроме того Lloyd закончил дискуссию тем, что исполнил какой-то шутовской номер, я воспринял это как признание им своей неправоты, улыбнулся и не стал продолжать.
> G>Не изменяет только в твоем абстрактном примере, а так всегда изменяет. > выделенное слишком сильное утверждение. мой пример, конечно, абстрактный. Но пример с ленивыми вычислениями/мемоизацией — вполне рабочий.
И с ленивыми вычислениями меняет. Иначе бы зачем их вводить?
Но ведь ты подразумеваешь несколько другое, дескать в общем смысле меняет, но для каких-то определенных задач можно сказать, что совсем даже не меняет
> G>Поскольку внутреннее состояние всегда изменяет поведение, то объекты с изменяющимися внутренними состояниями нельзя считать немутабельными. > Посыл неверный, вывод тоже.
Вижу, уперся рогом.
Собственно поэтому и просил ссылку.
> G>Такие определения лучше не вводить лишний раз. > Я ничего нового не вводил в этой теме. Идентичность, основанная на location, придумана не мной.
Я об определении немутабельности, которое подразумевает что немутабельность, это не совсем немутабельность, а такая немутабельность, что например ленивые объекты можно считать немутабельными. Вот такие определения, которые суть немножко не то, что написали, их тяжело в голове держать, я такие не люблю и предпочитаю выбрасывать.
Ссылочку плиз.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>на мой взгляд ни то ни другое. Про неравенство имени и именуемого объекта ты спорил уже с Lloyd-ом.
I>Ты передернул, я же написал "имя переменной == переменная", объекта там не было.
Я обобщил, объект здесь не объект ООП, а "именуемый именем объект". Если смущает "объект", пусть будет "именуемая именем шняга".
I>Кроме того Lloyd закончил дискуссию тем, что исполнил какой-то шутовской номер, я воспринял это как признание им своей неправоты, улыбнулся и не стал продолжать.
Из этого не следует что "имя переменной == переменная".
Здравствуйте, grosborn, Вы писали:
>> G>Не изменяет только в твоем абстрактном примере, а так всегда изменяет. >> выделенное слишком сильное утверждение. мой пример, конечно, абстрактный. Но пример с ленивыми вычислениями/мемоизацией — вполне рабочий.
G>И с ленивыми вычислениями меняет. Иначе бы зачем их вводить?
Смотря с какими, конечно. Если объект кричит о том, вычислялся он или нет, то конечно меняет. Однако, если по объекту сказать нельзя, то ничто не сможет указать на изменение его поведения.
G>Но ведь ты подразумеваешь несколько другое, дескать в общем смысле меняет, но для каких-то определенных задач можно сказать, что совсем даже не меняет
Нет, я подразумеваю конкретно наблюдаемое поведение объекта безотносительно задач.
>> G>Такие определения лучше не вводить лишний раз. >> Я ничего нового не вводил в этой теме. Идентичность, основанная на location, придумана не мной.
G>Я об определении немутабельности, которое подразумевает что немутабельность, это не совсем немутабельность, а такая немутабельность, что например ленивые объекты можно считать немутабельными. Вот такие определения, которые суть немножко не то, что написали, их тяжело в голове держать, я такие не люблю и предпочитаю выбрасывать. G>Ссылочку плиз.
Я давал, тебе не прокатило.
Здравствуйте, samius, Вы писали:
S>Из этого не следует что "имя переменной == переменная".
Ну так давай контрпример. Не про палец, который сначала показывает на Луну, затем на другой палец, затем оказывается вовсе не палец, а про переменную и отдельное от нее ее имя. Посмотрим, что это есть.
Здравствуйте, grosborn, Вы писали:
>> Покажи, как это можно обнаружить в коде.
G>Как минимум отладчиком
Отладчиком можно и изменить любой объект. Неизменяемые объекты — миф?
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Из этого не следует что "имя переменной == переменная".
I>Ну так давай контрпример. Не про палец, который сначала показывает на Луну, затем на другой палец, затем оказывается вовсе не палец, а про переменную и отдельное от нее ее имя. Посмотрим, что это есть.
Разные переменные могут иметь одно имя. Подумай над этим.
> G>Но ведь ты подразумеваешь несколько другое, дескать в общем смысле меняет, но для каких-то определенных задач можно сказать, что совсем даже не меняет > Нет, я подразумеваю конкретно наблюдаемое поведение объекта безотносительно задач.
Дай четкое определение, что это такое.
Немутабельный объект, это объект у которого
? не меняется конкретно наблюдаемое поведение объекта безотносительно задач ?
Потому что строго говоря, даже если ты ввел внутреннее поле в объекте, он как минимум занимает больше памяти, если ты изменил алгоритм, у него изменилось время работы и тд.
То есть строго говоря, изменение внутреннего состояния меняет его поведение.
Здравствуйте, grosborn, Вы писали:
>> G>Но ведь ты подразумеваешь несколько другое, дескать в общем смысле меняет, но для каких-то определенных задач можно сказать, что совсем даже не меняет >> Нет, я подразумеваю конкретно наблюдаемое поведение объекта безотносительно задач.
G>Дай четкое определение, что это такое. G>Немутабельный объект, это объект у которого G>? не меняется конкретно наблюдаемое поведение объекта безотносительно задач ?
Я давал ссылку. Оно тебя чем-то не устраивает, ты даже не можешь сформулировать, чем именно.
G>Потому что строго говоря, даже если ты ввел внутреннее поле в объекте, он как минимум занимает больше памяти, если ты изменил алгоритм, у него изменилось время работы и тд.
Ты время работы считаешь поведением? Интересно... Есть ли в твоей интерпретации объекты, чье поведение не меняется от вызова к вызову их методов?
G>То есть строго говоря, изменение внутреннего состояния меняет его поведение.
Т.е. тебе еще нужно дать определение состояния, поведения, идентичности, равенства и т.п.?
G>В общем нужно строгое определение.
Или что? Мне в общем случае без разницы, считаешь ли ты объекты с мемоизацией иммутабельными.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Разные переменные могут иметь одно имя. Подумай над этим.
I>Ты это к чему притянул и за что?
К тому что имя и переменная не есть одно и то же.
I>Имя употребленное без особого указания обозначает то, что оно именует. То есть в следующем списке два первых пункта обозначают одно и то же.
I>
I>i I>переменная i I>имя переменной i
По-моему ты это сам придумал. Для меня, например, "Вася" и "слесарь Вася", обозначают не одно и то же.
Здравствуйте, samius, Вы писали:
S>По-моему ты это сам придумал. Для меня, например, "Вася" и "слесарь Вася", обозначают не одно и то же.
Ну-ка, ну-ка. Представь себе, что ты сидишь со слесарем Васей за одним столом; в этом контексте и при отсутствии в нем других Вась, "Вася" и "слесарь Вася" именно одно и то же для тебя обозначают.
Здравствуйте, grosborn, Вы писали:
g> > Покажи, как это можно обнаружить в коде.
g> Как минимум отладчиком
Отладчик тут вообще не в тему. Вы же про язык как минимум и про парадигму (ООП) как максимум говорите. Каким образом тут отладчик влез? Он не является ни частью языка, ни частью обсуждаемых подходов проектирования.
Здравствуйте, samius, Вы писали:
S>Теперь представь себе, что ты сидишь за одним столом с двумя Васями, один из которых слесарь, а другой — кот. И ты утверждаешь что кот является слесарем Васей.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Теперь представь себе, что ты сидишь за одним столом с двумя Васями, один из которых слесарь, а другой — кот. И ты утверждаешь что кот является слесарем Васей.
I>В том-то и дело, что не было там кота.
Пока не начнешь отличать слесаря от кота, кота ты там и не заметишь.
I>(имя переменной == переменная) && (переменная != объект)
Переменная в императивных средах — это storage location.
Её семантика такова, что что мы туда положили, то мы и вытащили.
Имя переменной — это сущность ЯП.
Вот, например, в следующем коде — ровно одна переменная:
int a1 = 1;
int&a2 = a1;
А имён у неё две.
При этом в переменной вовсе не обязан храниться сам объект.
Например, в следующем коде переменная представляет адрес объекта:
typedef MyClass *pMyClass;
pMyClass p1 = new MyClass(1);
pMyClass &p2 = p1;
p2 = new MyClass(2);
Здесь по-прежнему два имени, одна переменная, и два объекта. Один из которых "утёк", т.к. переменных, хранящих его адрес, не осталось.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, grosborn, Вы писали:
G>Ссылочку-обоснование можно? Потому как в данном случае меняется внутреннее состояние объекта. Как бы получается противоречие определениям. Два немутабельных объекта становятся неидентичными и объекты не могут быть расположены в ридонли.
Это возможно только при противоречивых определениях.
1. Про неидентичность можно рассуждать только если явно отказаться от ООП-шной идентичности (там идентичность требует различать вообще любые два объекта). В остальных случаях лучше рассуждать в терминах эквивалентности.
2. Эквивалентность вовсе не обязана быть определена через побитовое сравнение состояний. Если операция эквивалентности определена так, чтобы игнорировать изменчивые компоненты состояния, то всё в порядке — объект, попавший в некий класс эквивалентности, никогда из него не выйдет, и может считаться иммутабельным.
3. Возможность расположить в ридонли в общем случае ортогональна понятию иммутабельности.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Переменная в императивных средах — это storage location.
осталось вот только обосновать, почему storage location не является объектом
S>Её семантика такова, что что мы туда положили, то мы и вытащили.
а объект как-то по другому сюда ведет? т.е. это ты так говоришь, как будто это должно противоречить поведению объекта.
S>Имя переменной — это сущность ЯП.
и че? опять же как это мешает переменной быть тоже объектом.
S>Вот, например, в следующем коде — ровно одна переменная: S>
S>int a1 = 1;
S>int&a2 = a1;
S>
S>А имён у неё две.
тут три объекта: 1, a1 и a2.
один из них — immutable: 1, один из них обладает ссылочной семантикой: a2.
не понятно чем этот код отличается от следующего кода. и почему во втором коде объекты, а в первом нет.
и эквивалентность между вышеуказанным кодом и кодом ниже — обеспечивает компилятор (или интерпретатор), скрывая всю эту кухню.
class Variable
{
public readonly string name;
public Variable(string name, int value){this.name = name; this.storage = value;}
int storage;
public int getValue(){return storage;}
public int setValue(int value){this.storage = value;}
}
class RefVariable
{
public RefVariable(string name, Variable var){this.name = name; this.var = var;}
public readonly string name;
Variable var;
public int getValue(){return var.getValue();}
public int setValue(int value){var.setValue(value);}
}
new RefVariable("a2", new Variable("a1", 1))
S>При этом в переменной вовсе не обязан храниться сам объект.
опять же ты так это говоришь, как будто это утверждение должно обосновывать почему переменную нельзя считать объектом.
S>Например, в следующем коде переменная представляет адрес объекта: S>
S>typedef MyClass *pMyClass;
S>pMyClass p1 = new MyClass(1);
S>pMyClass &p2 = p1;
S>p2 = new MyClass(2);
S>
S>Здесь по-прежнему два имени, одна переменная, и два объекта. Один из которых "утёк", т.к. переменных, хранящих его адрес, не осталось.
здесь 6 объектов (с различной семантикой)
два immutable: 1, 2, два неименнованых (new MyClass(1) и new MyClass(2)), и два именованных p1 и p2
опять же вышеприведенный код эквивалентен коду ниже, и соответственно стоит обосновать почему ниже объекты есть, а выше нету
class Variable<T>
{
public readonly string name;
public Variable(string name, T value){this.name = name; this.storage = value;}
T storage;
public T getValue(){return storage;}
public T setValue(T value){this.storage = value;}
}
class RefVariable<T>
{
public RefVariable(string name, Variable<T> var){this.name = name; this.var = var;}
public readonly string name;
Variable<T> var;
public T getValue(){return var.getValue();}
public T setValue(T value){var.setValue(value);}
}
new RefVariable<MyClass>("p2", new Variable<MyClass>("p1", new MyClass(1))).setValue(new MyClass(2))
Здравствуйте, DarkGray, Вы писали:
S>>И особенно переменную от объекта следует отличать в аспекте возможности изменения.
DG>отличать необходимо то, что отличается. DG>а переменная является частным случаем объекта, и обладает двумя методами(сообщениями) getValue/setValue, и соответственно константная переменная (или readonly-переменная) является immutable-объектом, обладающим одним методом getValue
неожиданный поворот. Ну что же, тогда я настаиваю что следует отличать "объект переменная" от "объекта значения", т.к. они в общем случае обладают различными ответственностями и наборами сообщений.
А если поковыряться, то окажется, что у переменной нет метода getValue, а вместо этого есть обязанность обеспечивать доставку сообщений объекту-значению. setValue тоже может не быть. Так, например, в C++ вместо setValue переменной работают конструкторы копирования/операторы присваивания значений. И работают они не с переменными, а со значениями.
В C# — да, можно считать что у переменной есть setValue. Но в C# нет возможности объявить неизменяемую переменную.
Здравствуйте, DarkGray, Вы писали: DG>где вводится именная такая идентичность? и как это свойство используется?
В определении.
Используется (совместно с концепцией ссылок) в возможности послать сообщение конкретному объекту, независимо от его внутреннего состояния.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали: DG>осталось вот только обосновать, почему storage location не является объектом
Для начала нужно как-то определить термин "объект". DG>а объект как-то по другому сюда ведет?
Смотря какой объект.
DG>тут три объекта: 1, a1 и a2. DG>один из них — immutable: 1, один из них обладает ссылочной семантикой: a2.
Гм. Опираясь на данные примеры, я могу заключить, что ваше определение термина "объект" эквивалентно определению термина "штуковина", или "сущность". То есть, вы называете объектом всё, что угодно.
Если нет — то жду определения в студии.
Утверждение про ссылочную семантику я вообще не понял. Отвлекаясь от определения объекта и вопроса о том, что же такое a1 и a2, хочу напомнить, что семантика у a1 и a2 совершенно одинаковая.
В C++ приведённый код вводит т.н. alias для a1, т.е. оба имени означают одно и то же.
DG>не понятно чем этот код отличается от следующего кода. и почему во втором коде объекты, а в первом нет.
Давайте вы приведёте определение термина "объект", и мы обсудим, что им является, а что — нет.
DG>и эквивалентность между вышеуказанным кодом и кодом ниже — обеспечивает компилятор (или интерпретатор), скрывая всю эту кухню.
Эквивалентность вышеуказанного кода и кода ниже никакой компилятор не обеспечит, т.к. код неэквивалентен.
В моём коде вы не сможете написать функцию Compare(x, y), которая бы вернула false для a1 и a2, при этом вернув true для a1 и a1.
В вашем коде банальный вызов Equals() расставит всё по своим местам.
А когда вы почините Equals() я вызову ReferenceEquals и снова получу то же, вид сбоку.
И только когда вы почините Equals и введёте непротиворечивую систему определений, мы сможем на примере вашей модели мира обсуждать разницу между переменной, её именем, и объектом, который хранится в этой переменной.
DG>
DG>class Variable
DG>{
DG> public readonly string name;
DG> public Variable(string name, int value){this.name = name; this.storage = value;}
DG> int storage;
DG> public int getValue(){return storage;}
DG> public int setValue(int value){this.storage = value;}
DG>}
DG>class RefVariable
DG>{
DG> public RefVariable(string name, Variable var){this.name = name; this.var = var;}
DG> public readonly string name;
DG> Variable var;
DG> public int getValue(){return var.getValue();}
DG> public int setValue(int value){var.setValue(value);}
DG>}
DG>new RefVariable("a2", new Variable("a1", 1))
DG>
S>>При этом в переменной вовсе не обязан храниться сам объект.
DG>опять же ты так это говоришь, как будто это утверждение должно обосновывать почему переменную нельзя считать объектом.
S>>Например, в следующем коде переменная представляет адрес объекта: S>>
S>>typedef MyClass *pMyClass;
S>>pMyClass p1 = new MyClass(1);
S>>pMyClass &p2 = p1;
S>>p2 = new MyClass(2);
S>>
S>>Здесь по-прежнему два имени, одна переменная, и два объекта. Один из которых "утёк", т.к. переменных, хранящих его адрес, не осталось.
DG>здесь 6 объектов (с различной семантикой) DG>два immutable: 1, 2, два неименнованых (new MyClass(1) и new MyClass(2)), и два именованных p1 и p2
DG>опять же вышеприведенный код эквивалентен коду ниже, и соответственно стоит обосновать почему ниже объекты есть, а выше нету DG>
DG>class Variable<T>
DG>{
DG> public readonly string name;
DG> public Variable(string name, T value){this.name = name; this.storage = value;}
DG> T storage;
DG> public T getValue(){return storage;}
DG> public T setValue(T value){this.storage = value;}
DG>}
DG>class RefVariable<T>
DG>{
DG> public RefVariable(string name, Variable<T> var){this.name = name; this.var = var;}
DG> public readonly string name;
DG> Variable<T> var;
DG> public T getValue(){return var.getValue();}
DG> public T setValue(T value){var.setValue(value);}
DG>}
DG>new RefVariable<MyClass>("p2", new Variable<MyClass>("p1", new MyClass(1))).setValue(new MyClass(2))
DG>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>неожиданный поворот. Ну что же, тогда я настаиваю что следует отличать "объект переменная" от "объекта значения",
согласен.
S> т.к. они в общем случае обладают различными ответственностями и наборами сообщений.
их можно считать полиморфными друг другу, тогда они будут обладать одним набором сообщений, но вот поведение — да, будет отличаться.
S>А если поковыряться, то окажется, что у переменной нет метода getValue, а вместо этого есть обязанность обеспечивать доставку сообщений объекту-значению.
можно рассматривать и такую модель, но такая модель требует больше информации для описания (более сложная)
S> setValue тоже может не быть. Так, например, в C++ вместо setValue переменной работают конструкторы копирования/операторы присваивания значений. И работают они не с переменными, а со значениями.
в C++ есть и setValue, и конструктор копирования, одно другому не мешает.
и присвоение выглядит как:
DG>>где вводится именная такая идентичность? и как это свойство используется? S>В определении. S>Используется (совместно с концепцией ссылок) в возможности послать сообщение конкретному объекту, независимо от его внутреннего состояния.
стот подчеркнуть где там написано, что требуется различать любые два объекта, как это было указано в цитате ниже
S> идентичность требует различать вообще любые два объекта
зы
отмечу, что из фразы на неформальном ЕЯ(на естественном языке) "объекты необходимо различать" автоматически не следует "любые два объекта должны быть различимы". это обусловленно тем, что ЕЯ оперирует в терминах нечетких логик, и в переводе на четкую логику слово "необходимо" будет означать "желательно; это обеспечит отличие от вырожденного случая".
например, когда прямоугольник определяется как штука с разными сторонами, из этого не следует прямого запрета на то, что квадрат и точка не являются прямоугольниками.
S>Гм. Опираясь на данные примеры, я могу заключить, что ваше определение термина "объект" эквивалентно определению термина "штуковина", или "сущность". То есть, вы называете объектом всё, что угодно. S>Если нет — то жду определения в студии.
вообще принято, что объект — это само по себе аксиоматическое понятие. все попытки его определить заканчиваются тем, что используются другие слова для описания того же самого.
конструктивный подход для таких неопределяемых понятий требует лишь, чтобы описывались свойства, которыми данное понятие обладает.
соответственно тогда:
объект — неопределяемое понятие, обладающее двумя свойствами:
1. объект имеет поведение (в том числе и вырожденное)
2. с объектом можно общаться посредством сообщений (запрос-ответ), в том числе возможны вырожденные варианты общения: запрос — есть, ответа — нет; запроса — нет, ответ — есть.
S>Утверждение про ссылочную семантику я вообще не понял. Отвлекаясь от определения объекта и вопроса о том, что же такое a1 и a2, хочу напомнить, что семантика у a1 и a2 совершенно одинаковая. S>В C++ приведённый код вводит т.н. alias для a1, т.е. оба имени означают одно и то же.
они выглядят для нас (как пользователей языка) одним и тем же, но ниоткуда не следует, что они являются одним и тем же. и в лучшем случае, только расковыряв каждый конкретный компилятор мы можем убедиться, что в данном конкретном компиляторе они являются одним и тем же.
зы
отмечу важное отличие — "выглядят для нас одинаковым" от "является одинаковым".
из второго следует, что он для всех является одинаковым (в том числе и для тех, кого мы не знаем и не представляем себе, и это очень сильное утверждение, если мы берем на себя смелость что-то утверждать про тех, кого не знаем и не представляем, и соответственно — должно очень строго доказываться), а из первого — это не следует.
ззы
и кстати, в следующем коде, насколько i является алиасом для x.y.z? и для чего именно он является алиасом? и в каких терминах эту семантику лучше записать?
int &a = x.y.z;
DG>>не понятно чем этот код отличается от следующего кода. и почему во втором коде объекты, а в первом нет. S>Давайте вы приведёте определение термина "объект", и мы обсудим, что им является, а что — нет.
см. выше.
DG>>и эквивалентность между вышеуказанным кодом и кодом ниже — обеспечивает компилятор (или интерпретатор), скрывая всю эту кухню. S>Эквивалентность вышеуказанного кода и кода ниже никакой компилятор не обеспечит, т.к. код неэквивалентен. S>В моём коде вы не сможете написать функцию Compare(x, y), которая бы вернула false для a1 и a2, при этом вернув true для a1 и a1. S>В вашем коде банальный вызов Equals() расставит всё по своим местам. S>А когда вы почините Equals() я вызову ReferenceEquals и снова получу то же, вид сбоку. S>И только когда вы почините Equals и введёте непротиворечивую систему определений, мы сможем на примере вашей модели мира обсуждать разницу между переменной, её именем, и объектом, который хранится в этой переменной.
это дурной тон — высечь то, чего не было в чужом сообщении.
семантика сравнений там не описывалась, потому что она не обсуждалась до этого.
если она требуется для данной дискуссии, я могу ее добавить.
Здравствуйте, DarkGray, Вы писали: DG>вообще принято, что объект — это само по себе аксиоматическое понятие.
Да щас прямо.
DG>конструктивный подход для таких неопределяемых понятий требует лишь, чтобы описывались свойства, которыми данное понятие обладает.
Совершенно верно.
DG>соответственно тогда: DG>объект — неопределяемое понятие, обладающее двумя свойствами: DG>1. объект имеет поведение (в том числе и вырожденное) DG>2. с объектом можно общаться посредством сообщений (запрос-ответ), в том числе возможны вырожденные варианты общения: запрос — есть, ответа — нет; запроса — нет, ответ — есть.
Если честно, я в среднем участвую в подобном ликбезе на тему математических основ ООП на RSDN в среднем ежегодно. Норму на этот год я уже выполнил. Поэтому никакого желания в очередной раз проходить вместе с вами по пути изобретения формальных определений поведения (которое определяется через "общение с объектом"), состояния, и идентичности я не испытываю.
DG>они выглядят для нас (как пользователей языка) одним и тем же, но ниоткуда не следует, что они являются одним и тем же. и в лучшем случае, только расковыряв каждый конкретный компилятор мы можем убедиться, что в данном конкретном компиляторе они являются одним и тем же.
Нет никакой нужды расковыривать компилятор. Если внутри языка они являются одним и тем же — значит, они являются одним и тем же. Это же математика — никакого "самого дела" нет, поэтому вопрос "а на самом деле они идентичны или нет" лишён смысла.
Они идентичны, если для них нельзя ввести отношение эквивалентности, разделяющее их в разне классы эквивалентности.
DG>зы DG>отмечу важное отличие — "выглядят для нас одинаковым" от "является одинаковым".
Если формализовать эти утверждения, то вы пытаетесь объяснить мне разницу между отношением идентичности и любым другим отношением эквивалентности. Спасибо, я в курсе.
DG>из второго следует, что он для всех является одинаковым (в том числе и для тех, кого мы не знаем и не представляем себе, и это очень сильное утверждение, если мы берем на себя смелость что-то утверждать про тех, кого не знаем и не представляем, и соответственно — должно очень строго доказываться),
Да, мы берём на себя смелость. Я уже предложил вам написать функцию на языке С++, которая введёт такое отношение эквивалентности, чтобы a1 и a2 оказались различными. Чтобы избежать недопонимания: препроцессор не считается.
DG>ззы DG>и кстати, в следующем коде, насколько i является алиасом для x.y.z? и для чего именно он является алиасом? и в каких терминах эту семантику лучше записать? DG>
DG>int &a = x.y.z;
DG>
Какую именно семантику вы хотите записать? a, в данном контексте, естественно, будет алиасом для x.y.z.
И вы точно так же не сможете различить их ни в какой функции Compare(x, y).
DG>это дурной тон — высечь то, чего не было в чужом сообщении. DG>семантика сравнений там не описывалась, потому что она не обсуждалась до этого.
Ну а как можно обсуждать вопросы идентичности, не обсуждая семантику сравнения?
DG>если она требуется для данной дискуссии, я могу ее добавить.
Я честно предупредил, что будет после того, как вы её добавите. Фактически, предлагаемые вами Variable и RefVariable могут "выглядеть одинаково", при условии, что мы не смотрим на них слишком внимательно (например, пользуемся только GetValue и SetValue). При этом они, очевидно, не "являются одинаковыми" в вашей терминологии. В отличие от имён a1 и a2 в моём примере, которые принадлежат одной и той же переменной.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>отмечу, что из фразы на неформальном ЕЯ(на естественном языке) "объекты необходимо различать" автоматически не следует "любые два объекта должны быть различимы". это обусловленно тем, что ЕЯ оперирует в терминах нечетких логик, и в переводе на четкую логику слово "необходимо" будет означать "желательно; это обеспечит отличие от вырожденного случая".
Это будет означать, что если у объектов нет свойства, позволяющего уверенно их различать, то у них нет идентичности. А поскольку идентичность является свойством самого объекта, а не пары объектов, то она не может то быть, то не быть. Значит, идентичность для объекта o1 — это его свойство, позволяющее нам отличать его от любого другого объекта. Например, мы отличили его от объекта o2. Значит, у o2 идентичность тоже есть. А раз она есть, значит она позволяет отличить и его от любого другого объекта.
Итого, если мы нашли что-то, с чем мы не можем проверить идентичность объекта o1, то это не объект. Или это — не идентичность.
Именно поэтому идентичность в ОО-моделях принято считать универсальной. То есть отношение identity(o1, o2) как минимум определено на всех объектах.
Я понимаю, чего вам хочется — объявить идентичностью произвольно выбранное отношение эквивалентности. Так тоже можно делать, но у такого выбора есть малоприятные последствия. В частности, для изменчивых объектов любое отношение эквивалентности либо будет эквивалентно идентичности, либо позволит объекту перебегать из одного класса эквивалентности в другой. Таким образом, объект может утратить определённую таким образом "идентичность".
DG>например, когда прямоугольник определяется как штука с разными сторонами, из этого не следует прямого запрета на то, что квадрат и точка не являются прямоугольниками.
Если прямоугольник определяется как штука с разными сторонами, то квадрат под него таки не подойдёт. Зато подойдёт треугольник. Именно поэтому никто не определяет прямоугольник таким образом.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Один набор сообщений — это спорно. объект-значение не имеет метода setValue: 1.setValue(2) — что-то нелепое.
такое сообщение есть, и оно даже отрабатывается, выдавая ошибку.
можешь сам попробовать написать 1 = 2 в любом языке, в котором '=' означает присвоение
S>Если поле объекта-переменной тоже считать объектом с методом setValue, то код выше представляет собой бесконечную рекурсию. Оно нам надо?
не надо так считать. те же самые обозначения лишь используются для того, чтобы не вводить новых сущностей.
также ряд понятий (как, например, присваивание) являются неопределяемыми, и можно лишь показать свойства, которыми они обладают.
что в данном случае и показывается. показывается, что работа с переменными не отличима от работы с объектами.
"а если что-то выглядит как кошка, то оно и является кошкой" (c).
S>Можно, но тогда придется считать неизменяемыми объекты, которые никто не менял по факту, а не по отсутствию возможности его изменения.
фраза построена так, что мне в ней видится намек на то, что это приведет к чему-то плохому.
это так и есть? но тогда, в чем опасность? или это мне лишь чудится.
тот же оптимизирующий компилятор, или там resharper — так и считает, когда, например, проводит оптимизации или refactoring, и этом им обеспечивает больше возможностей.
Еще раз другими словами: Сущности у нас две, из трех терминов: объект, переменная и имя переменной два будут означать одно и то же. Какие два — зависит от выбранной терминологии.
PS. Я говорю о различиях интересных с точки зрения программирования, а не лингвистики.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Sinclair, Вы писали:
S>>Вот, например, в следующем коде — ровно одна переменная:
I>
S>>int a1 = 1;
S>>int&a2 = a1;
I>
S>>А имён у неё две.
I>Разве? Согласно терминологии Danny Kalev здесь:
I>
I>An object in C++ is just a piece of memory, and a variable is the name by which the program refers to an object in the program. Plain and simple!
та еще терминология...
I>в твоем примере не одна переменная, а один объект, и не два имени переменной, а две переменные являющиеся именами этого объекта.
Но даже согласно этой терминлогии из фразы "and a variable is the name" не следует что "name (a2) is a variable".
I>An object in C++ is just a piece of memory, and a variable is the name by which the program refers to an object in the program. Plain and simple!
Давайте не будем путать беллетристику и computer science.
У Дэнни есть боле формальные определения, не сопровождающиеся ужимками типа "plain and simple"? Если мы посмотрим хотя бы сюда http://en.wikipedia.org/wiki/Variable_(programming), то окажется, что есть переменные (variable), а есть отдельные от них имена (variable identifier).
В данном случае как раз два идентификатора обозначают одну и ту же переменную.
I>Еще раз другими словами: Сущности у нас две, из трех терминов: объект, переменная и имя переменной два будут означать одно и то же. Какие два — зависит от выбранной терминологии.
Я показал два примера, из которых вам должно стать понятно, чем объект отличается от переменной, а переменная — от её имени. Все приведённые различия интересны с точки зрения программирования.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Я показал два примера, из которых вам должно стать понятно, чем объект отличается от переменной, а переменная — от её имени. Все приведённые различия интересны с точки зрения программирования.
Прошу прощения, заметив ошибку в первом примере, я не стал читать второго, а зря, потому-что там есть куда более очевидная ошибка:
S>При этом в переменной вовсе не обязан храниться сам объект. S>Например, в следующем коде переменная представляет адрес объекта:
S>typedef MyClass *pMyClass;
S>pMyClass p1 = new MyClass(1);
S>pMyClass &p2 = p1;
S>p2 = new MyClass(2);
S>Здесь по-прежнему два имени, одна переменная, и два объекта. Один из которых "утёк", т.к. переменных, хранящих его адрес, не осталось.
На самом деле здесь три объекта, поскольку указатель тоже объект. Переменных здесь две (одна из них ссылочная). Цитата из стандарта:
A variable is introduced by the declaration of a reference other than a non-static data member or of an
object.
S>Если честно, я в среднем участвую в подобном ликбезе на тему математических основ ООП на RSDN в среднем ежегодно. Норму на этот год я уже выполнил. Поэтому никакого желания в очередной раз проходить вместе с вами по пути изобретения формальных определений поведения (которое определяется через "общение с объектом"), состояния, и идентичности я не испытываю.
либо — это были плодотворные дискуссии, и значит ты сейчас можешь быстро в трех словах сформулировать свое конструктивное мнение по этому вопросу, либо — это была демагогия ни о чем, тогда у тебя есть возможность сейчас подисскутировать с умным человеком на эту тему.
DG>>они выглядят для нас (как пользователей языка) одним и тем же, но ниоткуда не следует, что они являются одним и тем же. и в лучшем случае, только расковыряв каждый конкретный компилятор мы можем убедиться, что в данном конкретном компиляторе они являются одним и тем же. S>Нет никакой нужды расковыривать компилятор. Если внутри языка они являются одним и тем же — значит, они являются одним и тем же. Это же математика — никакого "самого дела" нет, поэтому вопрос "а на самом деле они идентичны или нет" лишён смысла. S>Они идентичны, если для них нельзя ввести отношение эквивалентности, разделяющее их в разне классы эквивалентности.
разделяющие их на разные классы эквивалентности с точки зрения кого? и с точки зрения каких операций? это был ключевой вопрос в абзаце на который ты отвечал.
они эквиваленты лишь с точки зрения небольшого кол-ва операций над ними.
например, с точки зрения компилятора, resharper-а и т.д. — они не эквиваленты, и можно привести примеры когда эта эквивалентность нарушается с их точки зрения.
DG>>
DG>>int &a = x.y.z;
DG>>
S>Какую именно семантику вы хотите записать? a, в данном контексте, естественно, будет алиасом для x.y.z.
семантику того, что в коде ниже a ведет себя не как алиас для x.y.z, а вот как именно — семантика как раз и может показать.
S>И вы точно так же не сможете различить их ни в какой функции Compare(x, y).
если допустить, что ты говоришь правду, что это алиас для x.y.z, то следующий код должен выдать true(или 0), а это не так
int&a = x.y.z;
x.y = x.y1;
Compare(a, x.y.z);
значит это alias для чего-то другого, или a, вообще, не обладает семантикой алиаса
DG>>зы DG>>отмечу важное отличие — "выглядят для нас одинаковым" от "является одинаковым". S>Если формализовать эти утверждения, то вы пытаетесь объяснить мне разницу между отношением идентичности и любым другим отношением эквивалентности. Спасибо, я в курсе.
DG>>из второго следует, что он для всех является одинаковым (в том числе и для тех, кого мы не знаем и не представляем себе, и это очень сильное утверждение, если мы берем на себя смелость что-то утверждать про тех, кого не знаем и не представляем, и соответственно — должно очень строго доказываться), S>Да, мы берём на себя смелость. Я уже предложил вам написать функцию на языке С++, которая введёт такое отношение эквивалентности, чтобы a1 и a2 оказались различными. Чтобы избежать недопонимания: препроцессор не считается.
пожалуйста.
для:
int& GetValue(){int x = 5;return x;}
следующие два варианта кода обладают разным поведением. один периодически падает, другой нет.
int a = GetValue();
int &a = GetValue();
ты же не говорил, что конструкционную семантику ты выбрасываешь, которая отличается для переменной и ссылки.
и что ты считаешь их эквивалентными только с момента их создания.
int a1= 1;
int &a2 = a1;
или первую строку можно закоментировать, при этом вторая строка со ссылкой не скомпилится, а если закоментировать вторую, то всё будет нормально.
опять же когда ты говорил про эквивалентность, ты не говорил, что ты выкидываешь операции рефакторинга над этими сущностями.
т.е. ты рассматриваешь эквивалентность переменной и ссылки лишь на небольшом "части мира" — и это стоит осознавать, проговаривать и уж тем более признавать.
DG>>это дурной тон — высечь то, чего не было в чужом сообщении. DG>>семантика сравнений там не описывалась, потому что она не обсуждалась до этого. S>Ну а как можно обсуждать вопросы идентичности, не обсуждая семантику сравнения?
вообще-то обсуждали эквивалентность. вопрос идентичности появился чуть позже
если обсуждается вопрос: эквиваленты ли операции присвоения значения и получения значения из переменных a1, a2 операциям присвоения и получения значения из объектов Variable/RefVariable? то здесь нет нужды еще вводить идентичность Variable/RefVariable
вот если перейдем к вопросу обсуждения эквивалентности идентичности для одной пары и для другой, тогда стоит будет ввести.
DG>>если она требуется для данной дискуссии, я могу ее добавить. S>Я честно предупредил, что будет после того, как вы её добавите. Фактически, предлагаемые вами Variable и RefVariable могут "выглядеть одинаково", при условии, что мы не смотрим на них слишком внимательно (например, пользуемся только GetValue и SetValue). При этом они, очевидно, не "являются одинаковыми" в вашей терминологии. В отличие от имён a1 и a2 в моём примере, которые принадлежат одной и той же переменной.
все эти утверждения зависят от внимательности рассмотрения: и одинаковость a1 и a2, и одинаковость Variable/RefVariable, и эквивалентность переменных и объектов.
и стоит обосновать почему твой взгляд стоит считать самым внимательным.
Здравствуйте, DarkGray, Вы писали:
S>>Какую именно семантику вы хотите записать? a, в данном контексте, естественно, будет алиасом для x.y.z.
DG>семантику того, что в коде ниже a ведет себя не как алиас для x.y.z, а вот как именно — семантика как раз и может показать.
S>>И вы точно так же не сможете различить их ни в какой функции Compare(x, y).
DG>если допустить, что ты говоришь правду, что это алиас для x.y.z, то следующий код должен выдать true(или 0), а это не так
В C++ это так, если не говорить о C++/CLI с его property расширением, либо о трюках вроде #define y=foo()
S>Это будет означать, что если у объектов нет свойства, позволяющего уверенно их различать, то у них нет идентичности. А поскольку идентичность является свойством самого объекта, а не пары объектов, то она не может то быть, то не быть. Значит, идентичность для объекта o1 — это его свойство, позволяющее нам отличать его от любого другого объекта. Например, мы отличили его от объекта o2. Значит, у o2 идентичность тоже есть. А раз она есть, значит она позволяет отличить и его от любого другого объекта.
в этом рассуждении есть куча логических дыр, как минимум:
во-первых, у пары объектов идентичность легко может появляться или пропадать. хотя бы просто из-за того, что два объекта могут сливаться, а потом опять разделяться. как пример: два бегущих солнечных зайчика навстречу друг другу — будет момент когда они сольются и мы не сможем отличить один от другого, а потом они опять разделятся. и да, если ты опять рассматриваешь с точки зрения небольшой "части мира", например, с точки зрения своего любимого языка в котором объекты не умеют разделяться и объединяться, то сразу это ограничение указывай.
во-вторых, идентичность не является свойством самого по себе объекта. необходимо задать другие объекты, и необходимо задать набор операций на котором проверяется идентичность.
S>Я понимаю, чего вам хочется — объявить идентичностью произвольно выбранное отношение эквивалентности. Так тоже можно делать, но у такого выбора есть малоприятные последствия. В частности, для изменчивых объектов любое отношение эквивалентности либо будет эквивалентно идентичности, либо позволит объекту перебегать из одного класса эквивалентности в другой. Таким образом, объект может утратить определённую таким образом "идентичность".
ты так это говоришь, как будто это что-то плохое, и мы при этом что-то теряем. так что мы при этом теряем? и почему это плохо?
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Но даже согласно этой терминлогии из фразы "and a variable is the name" не следует что "name (a2) is a variable".
I>Тебя сбивают с толку лингвистические различия. "Подумай над этим".
В лингвистике отношение (Is-a) так же известно как "hyponym-hypernym relationship" (отношение частного и общего) или Subsumption(категоризация). Переменная здесь частное, имя — общее. И никак не наоборот.
S>В любом компилируемом языке до сообщения не доходит, т.к. ошибка времени компиляции, а не выполнения.
а ошибка компилятора — это что? знание данное нам свыше что ли? а не сообщение?
и потом ты как-то съехал на компиляторы, хотя на них мир не заканчивается.
DG>>не надо так считать. те же самые обозначения лишь используются для того, чтобы не вводить новых сущностей. S>Т.е. поле (которое на самом деле instance variable) объектом не считается, в отличии от local variable?
поле считается объектом, если мы умеем получать на него прямую ссылку. часто поле имеет ограничение, что оно доступно лишь косвенно через управляющий объект. в этом случается поле тоже можно рассматривать как объект, но придется вводить более сложное понятие — что такое ссылка, и какими свойствами она обладает.
DG>>также ряд понятий (как, например, присваивание) являются неопределяемыми, и можно лишь показать свойства, которыми они обладают. S>Полагаю что в конкретных языках присваивание определяемо. DG>>что в данном случае и показывается. показывается, что работа с переменными не отличима от работы с объектами. DG>>"а если что-то выглядит как кошка, то оно и является кошкой" (c). S>Но отличия есть. См. 1 = 2, &(a + 1), ...
для первого: переменной только на чтение тоже ничего присвоить нельзя.
второе зависит от языка: где-то можно получить ссылку на промежуточнее значения, где-то нельзя, где-то вообще нет понятия ссылки.
S>Опасность в том, что мы отойдем от определения неизменяемого объекта и начнем фантазировать. Придется вводить понятие контекста неизменяемости, т.к. объект не сможет быть неизменяемым в классическом понимании, но раз мы захотим называть его изменяемым, то нужно будет оговариваться, с какого момента он неизменяем, в каком контексте, на протяжении каких вычислений. Неизменяемость будет не атрибутом типа объекта, а атрибутом конкретного экземпляра в конкретных условиях.
почему это важно? почему нам необходимо для всех объектов всё время знать объект изменяем или нет?
почему нам недостаточно это знать (или получить/предоставить гарантию того или иного) только там, где это действительно необходимо, и только на тех операциях, которые нам необходимы.
DG>> тот же оптимизирующий компилятор, или там resharper — так и считает, когда, например, проводит оптимизации или refactoring, и этом им обеспечивает больше возможностей. S>Но для разработчика на стадии написания программы фактическая неизменяемость изменяемых объектов — слишком эфимерное понятие. Особенно, если оно никак не декларируется и не проверяется компилятором.
это противоречит тому, что утверждается, что хороший программист во всю оперирует готовыми паттернами, но при этом подразумевает их в уме, а не отливает каждое применение паттерна в программе в чугуне.
соответственно, immutable object — это такой же паттерн, и нет никакой необходимости его вовсю размечать в программе для того, чтобы им оперировать.
Здравствуйте, DarkGray, Вы писали:
S>>В любом компилируемом языке до сообщения не доходит, т.к. ошибка времени компиляции, а не выполнения.
DG>а ошибка компилятора — это что? знание данное нам свыше что ли? а не сообщение?
Ошибка компилятора это не сообщение в терминах ООП. DG>и потом ты как-то съехал на компиляторы, хотя на них мир не заканчивается.
Это ты съехал на компиляторы, попытавшись съехать на сообщения компиляторов с темы сообщений ООП. Или ты с самого начала подразумевал сообщения в более широком смысле, чем в ООП?
S>>Т.е. поле (которое на самом деле instance variable) объектом не считается, в отличии от local variable?
DG>поле считается объектом, если мы умеем получать на него прямую ссылку. часто поле имеет ограничение, что оно доступно лишь косвенно через управляющий объект. в этом случается поле тоже можно рассматривать как объект, но придется вводить более сложное понятие — что такое ссылка, и какими свойствами она обладает.
тогда как выглядит field=value в терминах setValue? Почему оно должно закончиться?
Для чего вообще нужна объектизация storage location, какие бенефиты она приносит?
DG>>>"а если что-то выглядит как кошка, то оно и является кошкой" (c). S>>Но отличия есть. См. 1 = 2, &(a + 1), ...
DG>для первого: переменной только на чтение тоже ничего присвоить нельзя.
Сначала мы должны отделить понятие переменной от значения, а уж потом определять свойство ее иммутабельности. Т.е. я полагаю что immutable variable прежде всего is a variable. DG>второе зависит от языка: где-то можно получить ссылку на промежуточнее значения, где-то нельзя, где-то вообще нет понятия ссылки.
А где-то нет понятия "переменной", а за него "name binding". В таком случае name — это тоже объект?
S>>Опасность в том, что мы отойдем от определения неизменяемого объекта и начнем фантазировать. Придется вводить понятие контекста неизменяемости, т.к. объект не сможет быть неизменяемым в классическом понимании, но раз мы захотим называть его изменяемым, то нужно будет оговариваться, с какого момента он неизменяем, в каком контексте, на протяжении каких вычислений. Неизменяемость будет не атрибутом типа объекта, а атрибутом конкретного экземпляра в конкретных условиях.
DG>почему это важно? почему нам необходимо для всех объектов всё время знать объект изменяем или нет? DG>почему нам недостаточно это знать (или получить/предоставить гарантию того или иного) только там, где это действительно необходимо, и только на тех операциях, которые нам необходимы.
А почему важно знать тип объекта? Не компилятору, решарперу, а разработчикам!
S>>Но для разработчика на стадии написания программы фактическая неизменяемость изменяемых объектов — слишком эфимерное понятие. Особенно, если оно никак не декларируется и не проверяется компилятором.
DG>это противоречит тому, что утверждается, что хороший программист во всю оперирует готовыми паттернами, но при этом подразумевает их в уме, а не отливает каждое применение паттерна в программе в чугуне. DG>соответственно, immutable object — это такой же паттерн, и нет никакой необходимости его вовсю размечать в программе для того, чтобы им оперировать.
Тогда и статическую типизацию можно подразумевать в уме. Нет никакой необходимости размечать программу типами.
DG>>а ошибка компилятора — это что? знание данное нам свыше что ли? а не сообщение? S>Ошибка компилятора это не сообщение в терминах ООП.
а что это тогда? если в терминах ООП?
если это для тебя невыразимо в терминах ООП, значит ты используешь плохой вариант модели ООП, которая может выражать лишь небольшую часть реальных задач.
DG>>и потом ты как-то съехал на компиляторы, хотя на них мир не заканчивается. S>Это ты съехал на компиляторы, попытавшись съехать на сообщения компиляторов с темы сообщений ООП. Или ты с самого начала подразумевал сообщения в более широком смысле, чем в ООП?
сообщение компилятора есть сообщение ООП.
могу даже так завернуть: сообщение об ошибке компиляции — есть сообщение от объекта 1, отправленное через компилятор о том, что 1 не поддерживает данный вид операций.
и на всякий случай сразу добавлю, что у нас нет возможности отличить — это нам единица шлет сообщения через компилятор или это компилятор нам придумывает сообщения. поэтому оба утверждения одинаково верны.
S>>>Т.е. поле (которое на самом деле instance variable) объектом не считается, в отличии от local variable?
DG>>поле считается объектом, если мы умеем получать на него прямую ссылку. часто поле имеет ограничение, что оно доступно лишь косвенно через управляющий объект. в этом случается поле тоже можно рассматривать как объект, но придется вводить более сложное понятие — что такое ссылка, и какими свойствами она обладает. S>тогда как выглядит field=value в терминах setValue?
допустим так (если поля больше трактуются, как свойства):
class FieldRef
{
FieldRef(T& item, const Field& field)
{
this.item = item;
this.field = field;
}
T &item;
const Field& field;
public void setValue(TValue value)
{
field.setValue(item, value);
}
}
S> Почему оно должно закончиться?
кто должен закончиться?
S>Для чего вообще нужна объектизация storage location, какие бенефиты она приносит?
эта эквивалентность используется при том же МП, например — при оптимизациях, или там при преобразовании обычного кода в cps, и т.д.
например, в C# — это используется для того, чтобы использовать переменные из внешнего контекста внутри делегата.
и компилятор сам автоматически преобразует переменные в объекты
//надуманный пример
Func<int, int> F()
{
int x = 1;
return (value) => {x += value; return x;};
}
S>Сначала мы должны отделить понятие переменной от значения, а уж потом определять свойство ее иммутабельности. Т.е. я полагаю что immutable variable прежде всего is a variable.
либо она immutable, либо она variable — а неизменное изменяемое — это как-то слишком.
DG>>второе зависит от языка: где-то можно получить ссылку на промежуточнее значения, где-то нельзя, где-то вообще нет понятия ссылки. S>А где-то нет понятия "переменной", а за него "name binding". В таком случае name — это тоже объект?
только в очень узких рамках.
так name — это зависимая(относительная) ссылка.
кстати, так переменные из компилируемой среды тоже можно интерпретировать, если есть необходимость.
S>А почему важно знать тип объекта? Не компилятору, решарперу, а разработчикам!
потому что они хотят знать, что можно делать в каждой конкретной строчке кода с данной штуковиной, а что нельзя.
при этом сам по себе тип им нафиг не нужен, а изменяемость/неизменяемость тем более.
им хочется знать что-то более конкретное: например, как получить ФИО человека, и будет ли оно уже отнормированное (например, что оно с большой буквы, что имя с начала, потом фамилия, что оно в именительном падеже и т.д.), или его надо нормировать, и что надо сделать, чтобы вывести только инициалы?
S>>>Но для разработчика на стадии написания программы фактическая неизменяемость изменяемых объектов — слишком эфимерное понятие. Особенно, если оно никак не декларируется и не проверяется компилятором.
поэтому лучше, например, договориться, что объекты, например, не изменяемы вообще (или как-то изменяемы особо) — как это сделали в ФЯ.
и жизнь сразу стала проще.
DG>>это противоречит тому, что утверждается, что хороший программист во всю оперирует готовыми паттернами, но при этом подразумевает их в уме, а не отливает каждое применение паттерна в программе в чугуне. DG>>соответственно, immutable object — это такой же паттерн, и нет никакой необходимости его вовсю размечать в программе для того, чтобы им оперировать. S>Тогда и статическую типизацию можно подразумевать в уме. Нет никакой необходимости размечать программу типами.
в целом, верно. в идеальном мире, компилятор (или IDE) без всякой разметки бы подсказал всё что необходимо знать об объекте. но мир пока неидеален, и компиляторы такое выделение информации из кода делают не охотно, поэтому приходится использовать ручной труд, и размечать самому.
в контексте неизменяемость/изменяемость — компилятор(или ide) могли бы сами подсказать, что мы пытаемся использовать изменяемую переменную, как неизменяемую. или что пытаемся поменять переменную, в то время, когда другой код уже заложился на то, что переменная не будет меняться.
DG>>>а ошибка компилятора — это что? знание данное нам свыше что ли? а не сообщение? S>>Ошибка компилятора это не сообщение в терминах ООП.
DG>а что это тогда? если в терминах ООП?
Я могу представить ООП систему, в которой компилятор шлет сообщения. Но 1 в этой системе не объект. DG>если это для тебя невыразимо в терминах ООП, значит ты используешь плохой вариант модели ООП, которая может выражать лишь небольшую часть реальных задач.
Да, плохой. А хорошую модель ООП ты сам придумал?
DG>>>и потом ты как-то съехал на компиляторы, хотя на них мир не заканчивается. S>>Это ты съехал на компиляторы, попытавшись съехать на сообщения компиляторов с темы сообщений ООП. Или ты с самого начала подразумевал сообщения в более широком смысле, чем в ООП?
DG>сообщение компилятора есть сообщение ООП. DG>могу даже так завернуть: сообщение об ошибке компиляции — есть сообщение от объекта 1, отправленное через компилятор о том, что 1 не поддерживает данный вид операций.
Во время компиляции 1 не является объектом. DG>и на всякий случай сразу добавлю, что у нас нет возможности отличить — это нам единица шлет сообщения через компилятор или это компилятор нам придумывает сообщения. поэтому оба утверждения одинаково верны.
Скорее они одинаково неверны, т.к. идентичности во время компиляции не наблюдаю.
S>>тогда как выглядит field=value в терминах setValue?
DG>допустим так (если поля больше трактуются, как свойства): DG>
Я вижу, ты определил поле с помощью поля и метод setValue через метод T::setValue. Это тавтология.
S>> Почему оно должно закончиться?
DG>кто должен закончиться?
вычисление. Поле при создании присваивает значение полю
S>>Для чего вообще нужна объектизация storage location, какие бенефиты она приносит?
DG>эта эквивалентность используется при том же МП, например — при оптимизациях, или там при преобразовании обычного кода в cps, и т.д.
DG>например, в C# — это используется для того, чтобы использовать переменные из внешнего контекста внутри делегата. DG>и компилятор сам автоматически преобразует переменные в объекты
Это не так. Замыкание трансформирует локальную переменную в поле класса, но никакой объектизации переменной там нет. Как была переменная storage location, так им и осталась. Изменяется лишь ее принадлежность.
S>>Сначала мы должны отделить понятие переменной от значения, а уж потом определять свойство ее иммутабельности. Т.е. я полагаю что immutable variable прежде всего is a variable.
DG>либо она immutable, либо она variable — а неизменное изменяемое — это как-то слишком.
Поле — это переменная класса. Верно? Как только мы его пометили const/readonly, оно перестало быть переменной? А что если не пометили, а просто не стали изменять?
S>>А где-то нет понятия "переменной", а за него "name binding". В таком случае name — это тоже объект?
DG>только в очень узких рамках. DG>так name — это зависимая(относительная) ссылка. DG>кстати, так переменные из компилируемой среды тоже можно интерпретировать, если есть необходимость.
Не понял.
S>>А почему важно знать тип объекта? Не компилятору, решарперу, а разработчикам!
DG>потому что они хотят знать, что можно делать в каждой конкретной строчке кода с данной штуковиной, а что нельзя. DG>при этом сам по себе тип им нафиг не нужен, а изменяемость/неизменяемость тем более.
изменяемость/неизменяемость тоже говорит о том, что можно делать с данной штуковиной.
DG>поэтому лучше, например, договориться, что объекты, например, не изменяемы вообще (или как-то изменяемы особо) — как это сделали в ФЯ. DG>и жизнь сразу стала проще.
Лучше, но мы говорим о том, нафига переменную считать объектом. С ФЯ тут как-то выпадаем из русла обсуждения.
DG>>>соответственно, immutable object — это такой же паттерн, и нет никакой необходимости его вовсю размечать в программе для того, чтобы им оперировать. S>>Тогда и статическую типизацию можно подразумевать в уме. Нет никакой необходимости размечать программу типами.
DG>в целом, верно. в идеальном мире, компилятор (или IDE) без всякой разметки бы подсказал всё что необходимо знать об объекте. но мир пока неидеален, и компиляторы такое выделение информации из кода делают не охотно, поэтому приходится использовать ручной труд, и размечать самому.
В целом и разметка неизменяемости нужна для того что бы улучшить диагностику.
DG>в контексте неизменяемость/изменяемость — компилятор(или ide) могли бы сами подсказать, что мы пытаемся использовать изменяемую переменную, как неизменяемую. или что пытаемся поменять переменную, в то время, когда другой код уже заложился на то, что переменная не будет меняться.
Не пойму, как компилятор может понять что мы используем изменяемую переменную как неизменяемую? или что код заложен на то, что переменная меняться не будет. Как выглядит код, который заложен на то, что переменная меняться будет?
var a = 1;
var b = 2;
Foo();
return a + b;
Что может сказать компилятор/IDE по такому коду? На что он заложен?
S>Да, плохой. А хорошую модель ООП ты сам придумал?
модель обычная. надо лишь умееть ее видеть в реальности и применять.
DG>>сообщение компилятора есть сообщение ООП. DG>>могу даже так завернуть: сообщение об ошибке компиляции — есть сообщение от объекта 1, отправленное через компилятор о том, что 1 не поддерживает данный вид операций. S>Во время компиляции 1 не является объектом.
ты можешь это проверить? доказать?
S>Я вижу, ты определил поле с помощью поля и метод setValue через метод T::setValue. Это тавтология.
да. потому что это делается под соусом: допустим мы уже все понимаем, что такое трудно-определимое понятие поле и как оно присваивается, но давайте напишем код (на нем же самом) который продемонстрирует семантику присвоения поля.
это из разряда, что ни кого не удивляет, что компилятор C++ написан на самом же C++.
если же нужна самораскрутка компилятора, то понятие поля можно вводить через списки или массивы, но мне лень, если честно.
S>Это не так. Замыкание трансформирует локальную переменную в поле класса, но никакой объектизации переменной там нет. Как была переменная storage location, так им и осталась. Изменяется лишь ее принадлежность.
по видимому я не понимаю, что такое storage location.
что такое storage location? и чем оно отличается для переменной и объекта?
S>Поле — это переменная класса. Верно? Как только мы его пометили const/readonly, оно перестало быть переменной? А что если не пометили, а просто не стали изменять?
мы можем перечислить тех, кто к полю имеет доступ, и в какое время или нет?
если не можем, то почему?
если можем, то значит можем и понять — переменная изменяемая или нет, и в какие промежутки.
DG>>так name — это зависимая(относительная) ссылка. DG>>кстати, так переменные из компилируемой среды тоже можно интерпретировать, если есть необходимость. S>Не понял.
для переменных в следующем куске кода
void F()
{
int a = 5;
int b = a + 4;
}
можно считать, что это есть пары ключ-значения из словаря F (который создается при старте функции F) с ключами "a" и "b" (или с ключами 0 и 1).
или если мы знаем, что тред один (а из под функции F ни в коем случае F еще раз вызываться не может), то тогда значения a и b можно размещать в глобальном dictionary с ключами "F.a" и "F.b"
и т.д.
S>Лучше, но мы говорим о том, нафига переменную считать объектом. С ФЯ тут как-то выпадаем из русла обсуждения.
ты что-то имеешь против ФЯ-шного ООП (или ООП-шного ФЯ)?
DG>>>>соответственно, immutable object — это такой же паттерн, и нет никакой необходимости его вовсю размечать в программе для того, чтобы им оперировать. S>>>Тогда и статическую типизацию можно подразумевать в уме. Нет никакой необходимости размечать программу типами.
DG>>в целом, верно. в идеальном мире, компилятор (или IDE) без всякой разметки бы подсказал всё что необходимо знать об объекте. но мир пока неидеален, и компиляторы такое выделение информации из кода делают не охотно, поэтому приходится использовать ручной труд, и размечать самому. S>В целом и разметка неизменяемости нужна для того что бы улучшить диагностику.
S>Не пойму, как компилятор может понять что мы используем изменяемую переменную как неизменяемую? S>или что код заложен на то, что переменная меняться не будет.
например, код вида
int a = GetValue1();
var r= Foo(a);
a = GetValue2();
var r2 = Bar(a);
return r + r2;
сигнализирует или о том, что или в нем есть ошибка (Foo не пересчитывается на основе изменения состояния a), или он требует рефакторинга (нарушается правило, что переменная должна использоваться лишь для хранения одной сущности)
S> Как выглядит код, который заложен на то, что переменная меняться будет?
цикл for определенно закладывается на то, что переменная цикла будет меняться.
S>
S>var a = 1;
S>var b = 2;
S>Foo();
S>return a + b;
S>
S>Что может сказать компилятор/IDE по такому коду? На что он заложен?
для начала код требует рефакторинга — зачем-то искусственно увеличено время жизни переменных a и b, хотя они используются только в конце программы.
можно сказать, что переменные immutable, каких-то сомнительных зависимостей нет
Здравствуйте, DarkGray, Вы писали:
S>>Да, плохой. А хорошую модель ООП ты сам придумал?
DG>модель обычная. надо лишь умееть ее видеть в реальности и применять.
Я не вижу как обычную модель ООП можно применить к сущностям времени выполнения во время компиляции.
DG>>>сообщение компилятора есть сообщение ООП. DG>>>могу даже так завернуть: сообщение об ошибке компиляции — есть сообщение от объекта 1, отправленное через компилятор о том, что 1 не поддерживает данный вид операций. S>>Во время компиляции 1 не является объектом в смысле времени выполнения.
DG>ты можешь это проверить? доказать?
Во время компиляции не работает доставка сообщений, object identity в том смысле, в котором они работают во время выполнения.
S>>Я вижу, ты определил поле с помощью поля и метод setValue через метод T::setValue. Это тавтология.
DG>да. потому что это делается под соусом: допустим мы уже все понимаем, что такое трудно-определимое понятие поле и как оно присваивается, но давайте напишем код (на нем же самом) который продемонстрирует семантику присвоения поля. DG>это из разряда, что ни кого не удивляет, что компилятор C++ написан на самом же C++.
DG>если же нужна самораскрутка компилятора, то понятие поля можно вводить через списки или массивы, но мне лень, если честно.
Я понимаю, что такое самораскрутка компилятора. Но не очень представляю себе как семантика поля может быть продемонстрирована с помощью рекурсивного типа данных с отстуствием выхода из рекурсии и рекурсивного метода без выхода из рекурсии в рамках eager языка.
S>>Это не так. Замыкание трансформирует локальную переменную в поле класса, но никакой объектизации переменной там нет. Как была переменная storage location, так им и осталась. Изменяется лишь ее принадлежность.
DG>по видимому я не понимаю, что такое storage location.
Интересно, ты понимаешь слишком широко модель ООП, но не понимаешь терминологии из спецификации языков. DG>что такое storage location? и чем оно отличается для переменной и объекта?
Это место для хранения. Переменная представляет собой место для хранения, а объект/значение хранится в этом месте.
S>>Поле — это переменная класса. Верно? Как только мы его пометили const/readonly, оно перестало быть переменной? А что если не пометили, а просто не стали изменять?
DG>мы можем перечислить тех, кто к полю имеет доступ, и в какое время или нет?
В общем случае нет. DG>если не можем, то почему?
Потому как не знаем все единицы компиляции/модули. DG>если можем, то значит можем и понять — переменная изменяемая или нет, и в какие промежутки.
даже если можем, то только в рамках одного потока выполнения.
DG>>>так name — это зависимая(относительная) ссылка. DG>>>кстати, так переменные из компилируемой среды тоже можно интерпретировать, если есть необходимость. S>>Не понял.
DG>для переменных в следующем куске кода DG>можно считать, что это есть пары ключ-значения из словаря F (который создается при старте функции F) с ключами "a" и "b" (или с ключами 0 и 1). DG>или если мы знаем, что тред один (а из под функции F ни в коем случае F еще раз вызываться не может), то тогда значения a и b можно размещать в глобальном dictionary с ключами "F.a" и "F.b" DG>и т.д.
И какой в этом смысл кроме издевательства над инкапсуляцией?
S>>Лучше, но мы говорим о том, нафига переменную считать объектом. С ФЯ тут как-то выпадаем из русла обсуждения.
DG>ты что-то имеешь против ФЯ-шного ООП (или ООП-шного ФЯ)?
Нет, я просто говорю что в рамках ФЯ (чистого) тема переменных бессмысленна.
S>>Не пойму, как компилятор может понять что мы используем изменяемую переменную как неизменяемую? S>>или что код заложен на то, что переменная меняться не будет.
DG>например, код вида DG>
DG>int a = GetValue1();
DG>var r= Foo(a);
DG>a = GetValue2();
DG>var r2 = Bar(a);
DG>return r + r2;
DG>
DG>сигнализирует или о том, что или в нем есть ошибка (Foo не пересчитывается на основе изменения состояния a)
Почему же это ошибка? DG>, или он требует рефакторинга (нарушается правило, что переменная должна использоваться лишь для хранения одной сущности)
Одной сущности? Так будет одна сущность?
int a = GetValue1(init_value);
var r= Foo(a);
a = GetValue1(a);
var r2 = Bar(a);
return r + r2;
Если не одна, тогда где разница между одной сущностью и не одной, например в цикле со счетчиком?
Если одна, то требует ли этот код рефакторинга? S>> Как выглядит код, который заложен на то, что переменная меняться будет?
DG>цикл for определенно закладывается на то, что переменная цикла будет меняться.
Понимаешь, когда переменная не меняется, компилятор может сказать, что она не меняется. Как только она стала меняться, компилятор скажет что код заточен под то, что она меняется.
S>>
S>>var a = 1;
S>>var b = 2;
S>>Foo();
S>>return a + b;
S>>
S>>Что может сказать компилятор/IDE по такому коду? На что он заложен?
DG>для начала код требует рефакторинга — зачем-то искусственно увеличено время жизни переменных a и b, хотя они используются только в конце программы. DG>можно сказать, что переменные immutable, каких-то сомнительных зависимостей нет
А если переменные статические?
Здравствуйте, DarkGray, Вы писали:
DG>в этом рассуждении есть куча логических дыр, как минимум: DG>во-первых, у пары объектов идентичность легко может появляться или пропадать. хотя бы просто из-за того, что два объекта могут сливаться, а потом опять разделяться. как пример: два бегущих солнечных зайчика навстречу друг другу — будет момент когда они сольются и мы не сможем отличить один от другого, а потом они опять разделятся.
Это всего лишь означает, что солнечные зайчики нельзя трактовать как объекты в ООП.
DG>во-вторых, идентичность не является свойством самого по себе объекта. необходимо задать другие объекты, и необходимо задать набор операций на котором проверяется идентичность.
Нет никакого набора операций для "проверки идентичности". Операция ровно одна — IsIdentic(o1, o2).
Я ещё раз поясню, если непонятно: отношением идентичности является особое отношение эквивалентности. Его особость — в том, что идентичные объекты невозможно различить никаким другим отношением эквивалентности.
DG>ты так это говоришь, как будто это что-то плохое, и мы при этом что-то теряем. так что мы при этом теряем? и почему это плохо?
По определению. Для того, чтобы что-то можно было трактовать как объект ООП, оно должно обладать идентичностью. Причём всегда, а не так, что с утра идентичность была, а в обед её уже нету. Потому, что это означает, что построенные на идентичности решения с утра работают, а после обеда — нет.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали: DG>ты ставишь всё с ног на голову. DG>сначала есть модель, которой мы хотим оперировать, и только потом появляется язык, который нам помогает этой моделью оперировать. DG>при этом модель самого конкретного языка нас интересует вообще постольку поскольку. DG>если необходимо, чтобы с точки зрения языка было необходимо, чтобы переменная была не отличима от объекта, то приходится к разрабам языка и говорится: хочу, и они это обеспечивают.
Первичность языка или модели совершенно неважна здесь. Важно то, что сейчас язык соответствует модели. И то, о свойствах элементов модели за пределами этой модели рассуждать смысла не имеет.
DG>тогда необходимо обосновать что это достаточно для решения реальных задач. а то иначе это напоминает анекдот, что я здесь ищу, потому что здесь светлее.
С чего вдруг? Мы не говорили о достаточности. Мы говорили только о необходимости.
DG>возьмем, как пример анонимный чат — там всё еще как-то понятно с точки зрения идентичности сообщений, но с идентичностью субъектов, которые эти сообщения постят — всё очень и очень непросто. но ведь необходимо и эту задачу уметь решать.
Не вижу формулировки проблемы. Опять же, нужно понимать, что мы говорим не о реальном мире, а о программировании. Нас вопросы идентичности реальных субъектов вообще никак не интересуют.
DG>или, например, возьмем машину — например, до какой степени машина идентична сама с собой по времени? по какому свойству определяется идентичность? по цвету, по номеру, по царапине на крыле?
И какое отношение это имеет к программированию?
DG>или есть даже брать чисто программисткие заморочки — объект хранящийся в базе, он же на сервере, а потом на клиенте — это один и тот же объект? или это три разных?
Это зависит от выбранной модели. Разве это не очевидно?
DG>и на всё это ответ один: DG>идентичность (и эквивалентность) имеет смысл только с точки зрения конкретной задачи с точки зрения конкретного набора операций и с точки зрения заданного набора объектов.
DG>и соответственно, следствия: DG> 1. два объекта могут одновременно быть эквиваленты (и не эквиваленты)
Именно поэтому отношение идентичности отличают от любого другого отношения эквивалентности. Последних может быть бесконечно много. В том числе и вырожденное отношение Equal(o1, o2) { return true;} вполне себе определяет некоторую эквивалентность. DG> 2. эквивалентность сама по себе нафиг не нужна, и не надо ее вводить, если она не требуется для задачи.
Задач, в которых не нужна никакая эквивалентность, практически не встречается.
S>>Я уже обосновал. Отложу продолжение разговора вплоть до написания функции compare, которая отличает a1 от a2. Или хотя бы a от x.y.z.
DG>жду продолжения
А, не ну если мы будем баловаться с небезопасными фичами C++, то можно сразу же забить на любые рассуждения о свойствах С++ программ.
Чтож, можно считать утверждение "a является алиасом для x.y.z" опровергнутым. Осталось из этого вывести опровержение изначального тезиса о том, что в приведённом мной фрагменте кода есть одна переменная с двумя именами.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, samius, Вы писали:
S>В лингвистике отношение (Is-a) так же известно как "hyponym-hypernym relationship" (отношение частного и общего) или Subsumption(категоризация). Переменная здесь частное, имя — общее. И никак не наоборот.
А это к чему? То, что лингвистика может различать понятия переменная и имя переменной, я не оспариваю. И даже с точки зрения программирования эти два понятия можно различать, но тогда переменная будет означать то же, что объект.
Z>>Люди, одумайтесь, вопрос выеденного яйца не стоит, просто некоторые готовы любую мысль довести до абсурда и и посчитать это философией.
DG>а что стоит обсуждать? что такое Nemerle? и почему то, что он делает следует называть МП?
Казалось бы при чем тут Nemerle.
По существу. Как я заметил, тебе как раз интересно обсуждать, что и как следует называть. Это может быть философским вопросом, но конкретно твои рассуждения по этому поводу контрконструктивны. Я уверен, что ты прекрасно понимаешь собеседника, но регулярно уводишь в лес обсуждения терминов где оттачиваешь демагогию.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>В лингвистике отношение (Is-a) так же известно как "hyponym-hypernym relationship" (отношение частного и общего) или Subsumption(категоризация). Переменная здесь частное, имя — общее. И никак не наоборот.
I>А это к чему? То, что лингвистика может различать понятия переменная и имя переменной, я не оспариваю.
Это я разжевываю смысл написанного в цитате, которую ты привел. I>И даже с точки зрения программирования эти два понятия можно различать, но тогда переменная будет означать то же, что объект.
Я тебя не пойму. Ты говоришь что их можно различать, но что это одно и то же
Нет, не будет переменная означать то же, что объект. Давай посмотрим еще раз на цитату, которую ты привел:
An object in C++ is just a piece of memory, and a variable is the name by which the program refers to an object in the program.
В этом предложении два утверждения (я не собираюсь оспаривать их истинность пока).
1. О том что объект это частный случай (подкатегория) куска памяти
2. О том что переменная это частный случай имени.
Иэ этих двух утверждений не следует, что переменная означает то же, что объект. Может быть ты не процитировал тот текст, из которого ты сделал такой вывод?
Неформально объект занимает память, а переменная предоставляет ее. Да, объект занимает ту самую память, которую предоставляет переменная. Но повода утверждать что переменная это то же что объект не больше, чем утверждать что банка из под пива тоже самое что и пиво на том основании, что пиво занимает емкость, предоставленную банкой.
Здравствуйте, samius, Вы писали:
S>Нет, не будет переменная означать то же, что объект.
В этом случае не будет, зато в этом случае (C++) имя переменной и переменная означают одно и то же с точки зрения программиста. Все зависит от соглашения, что договариваются называть словом переменная, либо переменная означает то же что объект, либо то же что имя переменной. В C++ никакой разницы между понятиями имя переменной и переменная нет.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Нет, не будет переменная означать то же, что объект.
I>В этом случае не будет, зато в этом случае (C++) имя переменной и переменная означают одно и то же с точки зрения программиста.
Если для тебя это одно и то же, то не надо подписывать сюда программистов в общем случае. Я тоже программист (и в том числе на C++), но различаю эти понятия.
I>Все зависит от соглашения, что договариваются называть словом переменная, либо переменная означает то же что объект, либо то же что имя переменной. В C++ никакой разницы между понятиями имя переменной и переменная нет.
Т.е. ты настаиваешь на каком-то соглашении, но не уверен, на каком именно?
Может дашь ссылку на компетентный источник, в котором бы было приведено такое соглашение? Только не как в прошлый раз, когда тебе пришлось расшифровывать то, о чем там написано с учетом лингвистических особенностей.
Еще раз, объект и переменную различать следует, хотя бы потому, что у них может быть разное время жизни. Переменную и имя переменной тоже следует отличать, т.к. одно может существовать без другого. В частности, в C++ имя существует во время разработки, а переменная — во время исполнения программы.
Здравствуйте, samius, Вы писали:
S>Если для тебя это одно и то же, то не надо подписывать сюда программистов в общем случае. Я тоже программист (и в том числе на C++), но различаю эти понятия.
DG>>ты можешь это проверить? доказать? S>Во время компиляции не работает доставка сообщений, object identity в том смысле, в котором они работают во время выполнения.
опять же это вопросы веры и не более.
вот если бы ты сказал: я тут проверил, и увидел, что конструкторы при компиляции не вызываются (потому что я в конструкторе винт форматирую, а при компиляции он не сформатировался), вот это уже было движение в правильном направлении — ты бы перешел от недоказуемых вещей к тому что есть на самом деле и то, что можно потрогать.
я могу, например, согласиться — что при компиляции нету еще классов и объектов, есть лишь их бледные проекции, потому что это можно проверить и этим можно управлять. и я утверждаю, что эти бледные проекции умеют посылать сообщения и это можно проверить, меняя листинг и получая сообщения на консоле компилятора.
S>Я понимаю, что такое самораскрутка компилятора. Но не очень представляю себе как семантика поля может быть продемонстрирована с помощью рекурсивного типа данных с отстуствием выхода из рекурсии и рекурсивного метода без выхода из рекурсии в рамках eager языка.
кроме самораскрутки компилятора, есть еще самораскрутка моделей.
нет там никакой рекурсии, потому что формально там язык A' описывается с помощью языка A.
и цепочка получается следующая:
допустим мы наивно знаем, что такое объект, поле, переменная и т.д., и что такое язык A, который оперирует этими понятиями.
для формализации понимания языка A построим язык A' и опишем его поведение и ожидаемые свойства, используя аппарат языка A.
описываем..
получившийся язык A' проверяем на эквивалентность языку A, если эквивалентности не наблюдается — корректируем понимание языка A.
S>>>Это не так. Замыкание трансформирует локальную переменную в поле класса, но никакой объектизации переменной там нет. Как была переменная storage location, так им и осталась. Изменяется лишь ее принадлежность.
DG>>по видимому я не понимаю, что такое storage location. S>Интересно, ты понимаешь слишком широко модель ООП, но не понимаешь терминологии из спецификации языков.
я не понимаю, как ты трактуешь те или иные понятия, и какой евангелие(ну там страуструпа, книгу дракона, буча или что-то еще) для этого используешь (раз уж зашел вопрос про веру)
DG>>что такое storage location? и чем оно отличается для переменной и объекта? S>Это место для хранения. Переменная представляет собой место для хранения, а объект/значение хранится в этом месте.
если мы делаем new MyObject(), то где здесь переменная и место для хранения?
DG>>если не можем, то почему? S>Потому как не знаем все единицы компиляции/модули.
тогда мы должны были как минимум специфицировать (явно или неявно) интерфейс доступа к нашей программе(нашей части), и зафиксировать через какие сообщения в какое время кто и каким образом имеем доступ.
также должны были зафиксировать жизненный цикл, инварианты состояний и т.д.
мы всё это сделали?
DG>>если можем, то значит можем и понять — переменная изменяемая или нет, и в какие промежутки. S>даже если можем, то только в рамках одного потока выполнения.
мы же вроде были в парадигме ООП, а там нет никаких потоков, а есть интерфейс и сообщения, а также спецификация в какое время какое сообщение должно приниматься.
DG>>>>так name — это зависимая(относительная) ссылка. DG>>>>кстати, так переменные из компилируемой среды тоже можно интерпретировать, если есть необходимость. S>>>Не понял.
DG>>для переменных в следующем куске кода DG>>можно считать, что это есть пары ключ-значения из словаря F (который создается при старте функции F) с ключами "a" и "b" (или с ключами 0 и 1). DG>>или если мы знаем, что тред один (а из под функции F ни в коем случае F еще раз вызываться не может), то тогда значения a и b можно размещать в глобальном dictionary с ключами "F.a" и "F.b" DG>>и т.д. S>И какой в этом смысл кроме издевательства над инкапсуляцией?
например, получить возможность сохранять и восстанавливать состояние программы(или ее части) в произвольный момент времени.
например есть код:
T F()
{
var a = Foo();
var b = Server_Bar();
return a + b;
}
и нам хочется его запускать в браузере, при этом Server_Bar — это серверная функция, и мы знаем, что она может работать долго, поэтому нам нужно уметь ее вызывать асинхронно, чтобы не подвешивать браузер.
это приводит к тому, что необходимо уметь прерывать работу программы на время вызова Server_Bar, а также уметь хранить текущее состояние.
соответственно, можно автоматически переписать эту программу к виду:
DG>>ты что-то имеешь против ФЯ-шного ООП (или ООП-шного ФЯ)? S>Нет, я просто говорю что в рамках ФЯ (чистого) тема переменных бессмысленна.
это в смысле использовать модель ФЯ, который чисто списковый. и что в этой модели хорошего? кроме того, что математики могут об этой модели что-то подоказывать?
DG>>сигнализирует или о том, что или в нем есть ошибка (Foo не пересчитывается на основе изменения состояния a) S>Почему же это ошибка?
потому что в реальных программах — такое поведение встречается с вероятностью 0.001% (условно)
соответственно, с вероятностью 99.999% — это ошибка.
DG>>, или он требует рефакторинга (нарушается правило, что переменная должна использоваться лишь для хранения одной сущности) S>Одной сущности? Так будет одна сущность? S>
S>int a = GetValue1(init_value);
S>var r= Foo(a);
S>a = GetValue1(a);
S>var r2 = Bar(a);
S>return r + r2;
S>
S>Если не одна, тогда где разница между одной сущностью и не одной, например в цикле со счетчиком?
сущность не одна и в этом куске кода.
разница в том, что паттерны, которые используют переменные повторно все на перечет, один из таких паттернов — это использование счетчика цикла. остальные использования — это ошибка, или какой-то новый паттерн, который тогда надо ввести.
DG>>цикл for определенно закладывается на то, что переменная цикла будет меняться. S>Понимаешь, когда переменная не меняется, компилятор может сказать, что она не меняется. Как только она стала меняться, компилятор скажет что код заточен под то, что она меняется.
чем это отличается от того, что программист сначала поставил const/readonly на переменную, а потом убрал?
или другими словами — какая такая информация есть у программиста, которая ему позволяет так делать, и какой информации не хватает компилятору?
S>А если переменные статические?
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>одна
I>Согласно стандарту все же две.
Ссылку/цитату в студию. Ты его как-то не так интерпретируешь.
Z> Я уверен, что ты прекрасно понимаешь собеседника, но регулярно уводишь в лес обсуждения терминов где оттачиваешь демагогию.
если человек делает утверждение (особенно сильные утверждения с кванторами все(всегда) и не существует(никогда)), он обязан понимать границы применимости своего утверждения.
соответственно, отвод в сторону — это лишь попытка проверить, а человек понимает, что его утверждение имеет границы, и что вот они только что были пересечены.
DG>>>ты можешь это проверить? доказать? S>>Во время компиляции не работает доставка сообщений, object identity в том смысле, в котором они работают во время выполнения.
DG>опять же это вопросы веры и не более. DG>вот если бы ты сказал: я тут проверил, и увидел, что конструкторы при компиляции не вызываются (потому что я в конструкторе винт форматирую, а при компиляции он не сформатировался), вот это уже было движение в правильном направлении — ты бы перешел от недоказуемых вещей к тому что есть на самом деле и то, что можно потрогать.
В самом деле? Ты считаешь что факт вызова конструктора имеет определяющее значение в модели ООП, но object identity это вопрос веры? У тебя какая-то своя модель.
DG>я могу, например, согласиться — что при компиляции нету еще классов и объектов, есть лишь их бледные проекции, потому что это можно проверить и этим можно управлять. и я утверждаю, что эти бледные проекции умеют посылать сообщения и это можно проверить, меняя листинг и получая сообщения на консоле компилятора.
ты можешь определить идентичность объектов, получая сообщения на консоли компилятора?
DG>кроме самораскрутки компилятора, есть еще самораскрутка моделей.
DG>нет там никакой рекурсии, потому что формально там язык A' описывается с помощью языка A. DG>и цепочка получается следующая: DG>допустим мы наивно знаем, что такое объект, поле, переменная и т.д., и что такое язык A, который оперирует этими понятиями.
Если мы знаем, что такое поле, то зачем язык А? DG>для формализации понимания языка A построим язык A' и опишем его поведение и ожидаемые свойства, используя аппарат языка A. DG>описываем.. DG>получившийся язык A' проверяем на эквивалентность языку A, если эквивалентности не наблюдается — корректируем понимание языка A.
Точно так же можно раскрутить модель, в которой поле в C++ будет записью в БД или вагоном РЖД. Так что твоя модель ничего не доказывает.
DG>>>по видимому я не понимаю, что такое storage location. S>>Интересно, ты понимаешь слишком широко модель ООП, но не понимаешь терминологии из спецификации языков.
DG>я не понимаю, как ты трактуешь те или иные понятия, и какой евангелие(ну там страуструпа, книгу дракона, буча или что-то еще) для этого используешь (раз уж зашел вопрос про веру)
википедию, спецификации
DG>>>что такое storage location? и чем оно отличается для переменной и объекта? S>>Это место для хранения. Переменная представляет собой место для хранения, а объект/значение хранится в этом месте.
DG>если мы делаем new MyObject(), то где здесь переменная и место для хранения?
а здесь нет переменной. Но формально здесь нет и объекта. Ты всего лишь попортил память.
S>>Потому как не знаем все единицы компиляции/модули.
DG>тогда мы должны были как минимум специфицировать (явно или неявно) интерфейс доступа к нашей программе(нашей части), и зафиксировать через какие сообщения в какое время кто и каким образом имеем доступ. DG>также должны были зафиксировать жизненный цикл, инварианты состояний и т.д. DG>мы всё это сделали?
ок, мы можем это сделать.
DG>>>если можем, то значит можем и понять — переменная изменяемая или нет, и в какие промежутки. S>>даже если можем, то только в рамках одного потока выполнения.
DG>мы же вроде были в парадигме ООП, а там нет никаких потоков, а есть интерфейс и сообщения, а также спецификация в какое время какое сообщение должно приниматься.
добро.
S>>И какой в этом смысл кроме издевательства над инкапсуляцией?
DG>например, получить возможность сохранять и восстанавливать состояние программы(или ее части) в произвольный момент времени.
А ее не было до этого? DG>например есть код: DG>
DG>T F()
DG>{
DG> var a = Foo();
DG> var b = Server_Bar();
DG> return a + b;
DG>}
DG>
DG>соответственно, можно автоматически переписать эту программу к виду: DG>
Ее можно автоматически переписать и без того что бы считать переменную рантайм объектом ООП.
DG>>>ты что-то имеешь против ФЯ-шного ООП (или ООП-шного ФЯ)? S>>Нет, я просто говорю что в рамках ФЯ (чистого) тема переменных бессмысленна.
DG>это в смысле использовать модель ФЯ, который чисто списковый. и что в этой модели хорошего? кроме того, что математики могут об этой модели что-то подоказывать?
Не понимаю, что значит чисто списковый. Я говорю о том, что флудить о переменных и их объектных моделях в контексте чистого ФЯ я не собираюсь.
DG>>>сигнализирует или о том, что или в нем есть ошибка (Foo не пересчитывается на основе изменения состояния a) S>>Почему же это ошибка?
DG>потому что в реальных программах — такое поведение встречается с вероятностью 0.001% (условно) DG>соответственно, с вероятностью 99.999% — это ошибка.
посчитать средне-арифметическое значений функции в заданных точках это ошибка с вероятностью 99.999%?
DG>сущность не одна и в этом куске кода. DG>разница в том, что паттерны, которые используют переменные повторно все на перечет, один из таких паттернов — это использование счетчика цикла. остальные использования — это ошибка, или какой-то новый паттерн, который тогда надо ввести.
Т.е. ты предлагаешь поделить весь код на паттерны известные и неизвестные компилятору? И о неизвестных кричать что это ошибка?
DG>>>цикл for определенно закладывается на то, что переменная цикла будет меняться. S>>Понимаешь, когда переменная не меняется, компилятор может сказать, что она не меняется. Как только она стала меняться, компилятор скажет что код заточен под то, что она меняется.
DG>чем это отличается от того, что программист сначала поставил const/readonly на переменную, а потом убрал? DG>или другими словами — какая такая информация есть у программиста, которая ему позволяет так делать, и какой информации не хватает компилятору?
У программиста есть намерение использовать этот объект определенным образом и предотвратить использование его другими способами. А компилятор может только догадываться о том, что хочет программист, причем постфактум. Если у программиста есть намерение сделать объект иммутабельным, но нет способа сказать об этом компилятору, компилятор будет считать объект мутабельным по его использованию.
S>>А если переменные статические?
DG>код требует рефакторинга.
Допустим. Так что скажет компилятор?
DG>>я могу, например, согласиться — что при компиляции нету еще классов и объектов, есть лишь их бледные проекции, потому что это можно проверить и этим можно управлять. и я утверждаю, что эти бледные проекции умеют посылать сообщения и это можно проверить, меняя листинг и получая сообщения на консоле компилятора. S>ты можешь определить идентичность объектов, получая сообщения на консоли компилятора?
с какой-то точностью — да.
S>Точно так же можно раскрутить модель, в которой поле в C++ будет записью в БД или вагоном РЖД. Так что твоя модель ничего не доказывает.
можно. и если она к тому же будет эквивалентной исходной на каком-то подмножестве операций, то это нам позволит утверждать, что C++-программу, которая использует только эти операции, можно напрямую(без введения ВМ) выполнить в БД или с помощью вагонов РЖД.
DG>>если мы делаем new MyObject(), то где здесь переменная и место для хранения? S>а здесь нет переменной. Но формально здесь нет и объекта. Ты всего лишь попортил память.
и каковы границы этого утверждения?
S>Ее можно автоматически переписать и без того что бы считать переменную рантайм объектом ООП.
покажи чем мы ее при этом считаем, и на основании каких утверждений мы переписываем программу.
DG>>потому что в реальных программах — такое поведение встречается с вероятностью 0.001% (условно) DG>>соответственно, с вероятностью 99.999% — это ошибка. S>посчитать средне-арифметическое значений функции в заданных точках это ошибка с вероятностью 99.999%?
и где там вызов функции от изменяемой переменной (кроме вызовов от изменяемой переменной цикла, которая пробегает по заданным точкам)?
DG>>сущность не одна и в этом куске кода. DG>>разница в том, что паттерны, которые используют переменные повторно все на перечет, один из таких паттернов — это использование счетчика цикла. остальные использования — это ошибка, или какой-то новый паттерн, который тогда надо ввести. S>Т.е. ты предлагаешь поделить весь код на паттерны известные и неизвестные компилятору? И о неизвестных кричать что это ошибка?
в первом приближении, да.
DG>>код требует рефакторинга. S>Допустим. Так что скажет компилятор?
скажет, что программа требует рефакторинга, и что откомпилированный результат лучше выбросить, если есть возможность.
S>У программиста есть намерение использовать этот объект определенным образом и предотвратить использование его другими способами. А компилятор может только догадываться о том, что хочет программист, причем постфактум. Если у программиста есть намерение сделать объект иммутабельным, но нет способа сказать об этом компилятору, компилятор будет считать объект мутабельным по его использованию.
программист это решение принял на основании какой-то информации (а не просто потому что так захотела его левая пятка)
соответственно, я еще раз спрашиваю — какая информация есть у программиста, которой нет у компилятора?
Здравствуйте, DarkGray, Вы писали:
DG>так вроде тогда правильный ответ, что надо строить решения на чем-то другом (например, на частичной идентичности), и жизнь сразу наладится. разве нет?
С нетерпением жду новой парадигмы программирования, построенной на частичной идентичности. Она, надо полагать, придёт на смену ООП, которое так требовательно к идентичности.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>С нетерпением жду новой парадигмы программирования, построенной на частичной идентичности. Она, надо полагать, придёт на смену ООП, которое так требовательно к идентичности.
ты лучше ответь на следующее:
DG> можем ли мы одновременно использовать две модели: одна которая утверждает что это идентичные объекты, а другая — что это разные? DG> или другими словами: можем ли мы использовать модель — которая в одной части утверждений считает, что это идентичные объекты, а в другой части утверждений считает, что это неидентичные объекты?
Здравствуйте, DarkGray, Вы писали:
DG>речь идет именно о достаточности. потому что, например, модель вида "здесь используем идентичность, здесь — не используем, а здесь используем частичную идентичность; DG>здесь используем булеву логику, а здесь используем другую логику" включает в себя модель "мы только работаем с объектами с постоянной идентичностью и только с булевой логикой".
А ещё модель машины тьюринга с неизвестным количеством ошибок (то есть при чтении с ленты получаем не тот символ, котроый там записан) включает в себя модель машины тьюринга с нулём ошибок.
Давайте поставим ребром вопрос о достаточности МТ с нулевым количеством ошибок для описания произвольных алгоритмов.
DG>вот этот постулат не понятен. DG>программирование мы используем для того, чтобы решать какие-то задачи в реальном мире, а не само по себе в вакууме.
DG>и соответственно, если мы даже в реальном мире не можем разобраться на многих задачах с идентичностью, а программист утверждает, что он готов решать только задачи, где есть строгая идентичность, то получается — а нафиг нам такое программирование и такой программист, который нам ничем помочь не может?
Налицо передёргивание. Совершенно непонятно, каким это образом вы перешли от строгости модели программирования к её непригодности для решения реальных задач. Если следовать вашей логике, то преобразование Фурье нафиг не нужно, т.к. в нём используется интеграл с бесконечными пределами, а в природе бывают исключительно сигналы конечной длительности.
Да вообще всю математику нужно выкинуть на помойку, т.к. она оперирует исключительно идеальными объектами, в то время, как в жизни у нас ничего идеального заведомо нет.
Если же перестать заниматься демагогией, то станет понятно, что для программного решения задачи совершенно нет нужды моделировать недостатки реального мира.
DG>потому что программирование это перевод реальности в модель. соответственно, если в реальности нет строгой идентичности между объектами, то откуда она появится в модели?
Зададим, и появится. Зачем вы пишете этот бред? У нас нет нужды создать копию машины на молекулярном уровне внутри компьютера.
У нас есть задача автоматизировать некоторые действия. С точки зрения сервиса по прокату автомобилей, все автомобили в пределах одного класса эквивалентны. Тем не менее, конкретный автомобиль, выданный вам в начале срока проката, будет вполне себе идентичен только самому себе при возврате в конце срока проката. Независимо от наличия либо отсутствия царапин.
Попробуйте для эксперимента вернуть не тот автомобиль, привлекая ваши философские экзерсисы типа "автомобиль сегодня не может быть идентичен автомобилю вчера, ибо нельзя войти дважды в одну и ту же реку".
DG>можем ли мы одновременно использовать две модели: одна которая утверждает что это идентичные объекты, а другая — что это разные?
Что значит "одновременно использовать две модели"? Объект входит ровно в одну модель. Если вам хочется построить другую модель — на здоровье, в ней будут другие объекты, в общем случае никак не связанные с объектами в первой модели. DG>или другими словами: можем ли мы использовать модель — которая в одной части утверждений считает, что это идентичные объекты, а в другой части утверждений считает, что это неидентичные объекты?
Нет, не можем. По определению идентичности. Как вы себе представляете "одну часть" и "другую часть" утверждений, если сама по себе идентичность — это ровно одно отношение?
DG>так я тебе сразу говорил, что про эквивалентность можно лишь говорить на каком-то наборе операций, и что стоит это сразу оговаривать. В данном случае, ты рассматриваешь эквивалентность лишь на наборе безопасных операций.
Давайте введём в студию формальное определение "эквивалентности на наборе операций". Лично мне это словосочетание непонятно.
Для эквивалентности необходимо и достаточно ровно одной операции: процедуры сравнения объектов.
DG>но ты не стал это слушать, а начал бегать с шашкой и кричать: что в моем любимом языке можно утверждать, что переменная и ссылка — эквивалентны всегда безотносительно набора операций.
Я не делал такого утверждения. Я говорил, что имя переменной и переменная — не одно и то же.
DG>соответственно, я также утверждаю, что переменные и объекты эквиваленты между собой на "безопасном"-наборе: получить/записать значение
К сожалению, это утверждение всё ещё легко опровергнуть. Я уже давно показал пример, в котором есть одна переменная, и два объекта. Очевидно, что, т.к. объекты не эквивалентны между собой, то и переменной они эквивалентны быть не могут.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>ты можешь определить идентичность объектов, получая сообщения на консоли компилятора?
DG>с какой-то точностью — да.
Продемонстрируй, как будет выглядеть проверка с помощью консоли компилятора идентичности объектов, на которые ссылаются a и b.
DG>можно. и если она к тому же будет эквивалентной исходной на каком-то подмножестве операций, то это нам позволит утверждать, что C++-программу, которая использует только эти операции, можно напрямую(без введения ВМ) выполнить в БД или с помощью вагонов РЖД.
Но такая модель не делает поле объекта вагоном.
DG>>>если мы делаем new MyObject(), то где здесь переменная и место для хранения? S>>а здесь нет переменной. Но формально здесь нет и объекта. Ты всего лишь попортил память.
DG>и каковы границы этого утверждения?
Оно справедливо в границах ООП в том случае если конструктор прямо или косвенно не записал this куда-нибудь. ООП не рассматривает объекты, которым нельзя отправить сообщение либо проверить идентичность.
S>>Ее можно автоматически переписать и без того что бы считать переменную рантайм объектом ООП.
DG>покажи чем мы ее при этом считаем, и на основании каких утверждений мы переписываем программу.
Мы ее ничем не считам. Допустим, что мы можем наблюдать узел AST, который может превратиться в переменную. Но нет никаких оснований считать что узел АСТ имеет какое-то отношение к некой переменной, особенно ввиду того, что сей узел будет заменен на кусок АСТ, представляющий обращение к некому кэшу.
DG>>>потому что в реальных программах — такое поведение встречается с вероятностью 0.001% (условно) DG>>>соответственно, с вероятностью 99.999% — это ошибка. S>>посчитать средне-арифметическое значений функции в заданных точках это ошибка с вероятностью 99.999%?
DG>и где там вызов функции от изменяемой переменной (кроме вызовов от изменяемой переменной цикла, которая пробегает по заданным точкам)?
Например, вызов функции суммирования агрегата с очередным значением.
S>>Т.е. ты предлагаешь поделить весь код на паттерны известные и неизвестные компилятору? И о неизвестных кричать что это ошибка? DG>в первом приближении, да.
О втором приближении боюсь спрашивать.
DG>>>код требует рефакторинга. S>>Допустим. Так что скажет компилятор?
DG>скажет, что программа требует рефакторинга, и что откомпилированный результат лучше выбросить, если есть возможность.
Выбросить работающий код потому что он не соответствует паттернам, заложенным в компилятор? Боюсь, что немногие будут пользоваться таким компилятором.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
I>
I>A variable is introduced by the declaration of a reference other than a non-static data member or of an
I>object.
S>>Эта цитата не говорит о том что в примере выше две переменных.
I>Эта цитата говорит о том, что объявление ссылки "вводит" (новую) переменную.
Уточни, пожалуйста, оно говорит о каких-то конкретных случаях объявления ссылки, или о всех, включая объявление ссылки на локальную переменную?
S>>У программиста есть намерение использовать этот объект определенным образом и предотвратить использование его другими способами. А компилятор может только догадываться о том, что хочет программист, причем постфактум. Если у программиста есть намерение сделать объект иммутабельным, но нет способа сказать об этом компилятору, компилятор будет считать объект мутабельным по его использованию.
DG>программист это решение принял на основании какой-то информации (а не просто потому что так захотела его левая пятка) DG>соответственно, я еще раз спрашиваю — какая информация есть у программиста, которой нет у компилятора?
Собственно так бывает, что сначала левая пятка программиста захотела сделать объект мутабельным, а потом она же захотела сделать его иммутабельным. Может программист покурил чего до того или после и у программиста появились какие-то соображения. Может его на форуме кто надоумил. Компилятору нужна такая информация?
Здравствуйте, DarkGray, Вы писали:
DG>> можем ли мы одновременно использовать две модели: одна которая утверждает что это идентичные объекты, а другая — что это разные? DG>> или другими словами: можем ли мы использовать модель — которая в одной части утверждений считает, что это идентичные объекты, а в другой части утверждений считает, что это неидентичные объекты?
DG>если не можем, то почему?
По определению. Я приводил определение идентичности. Оно устроено так, что идентичность может быть только одна. Если есть два отношения, I1 и I2, при этом одно из отношений различает объекты o1 и o2, а второе — нет, то второе не является идентичностью. В лучшем случае оно является отношением эквивалентности.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, samius, Вы писали:
S>Уточни, пожалуйста, оно говорит о каких-то конкретных случаях объявления ссылки, или о всех, включая объявление ссылки на локальную переменную?
О всех кроме ссылок являющихся "non-static data member".
DG>>так я тебе сразу говорил, что про эквивалентность можно лишь говорить на каком-то наборе операций, и что стоит это сразу оговаривать. В данном случае, ты рассматриваешь эквивалентность лишь на наборе безопасных операций. S>Давайте введём в студию формальное определение "эквивалентности на наборе операций". Лично мне это словосочетание непонятно. S>Для эквивалентности необходимо и достаточно ровно одной операции: процедуры сравнения объектов.
стыдно должно быть — этого малого, еще как минимум, необходимо то, что сравнивается на эквивалентность.
давай фиксировать — а что же мы сравниваем.
возьмем задачу эквивалентности переменных и ссылок (назовем их элементами).
при этом мы сравниваем эквивалентность их поведения:
берем переменную и ссылку в одинаковом(эквивалентном) состоянии,
берем какую-нибудь операцию над переменной (и подобную ей над ссылкой) и применяем, получая результат для переменной и ссылки,
далее сравниваем результаты на одинаковость(эквивалентность).
дальше рассматриваем применение всех таких операций для всех состояний — если одинаковость(эквивалентность) всегда сохранялась, значит мы делаем вывод, что поведение данных элементов эквивалентно
соответственно алгоритм проверки эквивалентности поведения двух элементов потребовал:
функцию проверки эквивалетности состояния двух элементов
набор пар операций (для одного элемента и соответствующей ей для другого элемента)
вот эту штуку мы можем назвать: эквивалентность на наборе операций (или более строже: эквивалентность поведения элементов X и Y на наборе операций Z с функцией эквивалентности между элементами E(X,Y))
S>Теперь референсы формально считаются переменными, невзирая на то, что память для хранения значения может и не выделиться. И просто потому что так меньше исправлять в стандарте.
т.е. ты предлаешь написать в стандарте, что ссылка может является переменной, а может нет?
S>>Теперь референсы формально считаются переменными, невзирая на то, что память для хранения значения может и не выделиться. И просто потому что так меньше исправлять в стандарте.
DG>т.е. ты предлаешь написать в стандарте, что ссылка может является переменной, а может нет?
нет, я поражаюсь, как легко можно изменить терминологию, устоявшуюся десятилетиями.
DG>давай фиксировать — а что же мы сравниваем. DG>возьмем задачу эквивалентности переменных и ссылок (назовем их элементами). DG>при этом мы сравниваем эквивалентность их поведения:
Ключевое слово, пропущенное ранее, выделено. Дальнейшее, конечно же, понятно.
С точностью до ошибок (или нестрогостей)
Ну, вот к примеру:
берем какую-нибудь операцию над переменной (и подобную ей над ссылкой) и применяем, получая результат для переменной и ссылки
К кому из элементов мы применяем эту операцию?
DG>вот эту штуку мы можем назвать: эквивалентность на наборе операций (или более строже: эквивалентность поведения элементов X и Y на наборе операций Z с функцией эквивалентности между элементами E(X,Y))
Ну, вот теперь всё становится более-менее понятным.
Давайте теперь попробуем всё же нарисовать пример, в котором нарушается эквивалентность поведения между a и a1:
int a = 1;
int &a1 = a;
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, igna, Вы писали:
I>На самом деле здесь три объекта, поскольку указатель тоже объект. Переменных здесь две (одна из них ссылочная). Цитата из стандарта:
Ок, без проблем. Тем не менее, количество переменных и количество объектов не совпадают, какие бы мы терминологические ухищрения ни принимали.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Ну, вот теперь всё становится более-менее понятным. S>Давайте теперь попробуем всё же нарисовать пример, в котором нарушается эквивалентность поведения между a и a1: S>
S>int a = 1;
S>int &a1 = a;
S>
на вскидку должны быть эквивалентны, но из эквивалентности переменной и ссылки на одном примере не следует, что ссылка и переменная эквиваленты всегда.
DG>>давай фиксировать — а что же мы сравниваем. DG>>возьмем задачу эквивалентности переменных и ссылок (назовем их элементами). DG>>при этом мы сравниваем эквивалентность их поведения: S>Ключевое слово, пропущенное ранее, выделено. Дальнейшее, конечно же, понятно.
специфицируй тогда эквивалентность каких объектов ты сравнивал и с помощью какой процедуры. а то пальцем тыкать каждый может..
Здравствуйте, DarkGray, Вы писали:
DG>на вскидку должны быть эквивалентны, но из эквивалентности переменной и ссылки на одном примере не следует, что ссылка и переменная эквиваленты всегда.
Такого утверждения никто не делал. Зачем вы пытаетесь его опровергать?
Вам дали пример того, как у одной переменной появляется два имени. А вы начинаете махать шашкой и рассказывать, как невозможно моделировать реальные автомобили при помощи ООП из-за того, что в реальном мире вопрос идентичности автомобилей крайне запутан.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>специфицируй тогда эквивалентность каких объектов ты сравнивал и с помощью какой процедуры. а то пальцем тыкать каждый может..
Я утверждал, что после такого определения a и a1 не существует способа написать функцию двух аргументов сompare(), которая бы вернула true, если в неё переданы a и a, и false, если в неё переданы a и a1.
При этом можно проводить любые манипуляции с a и/или a1, оставаясь в рамках языка.
Текстовые игры, типа препроцессора, запрещены — т.е. мы сначала натравливаем на программу препроцессор, а потом смотрим, удовлетворяет ли нас исходник.
То есть вот такое "очевидное" решение не проходит:
bool compare(int x, int y)
{
return (x == y);
}
int a = 1;
int &a1 = a;
#define a1 0
cout << compare(a, a1)
Всё это имеет целью доказать, что a1 — это ещё одно имя (алиас) для a, а не новая отдельная переменная (да, это противоречит терминологии нового стандарта, как мы уже выяснили в соседней ветке)
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>там же написано: операций пара: одна над переменной F(X) другая подобная над ссылкой F(Y) DG>соответственно: DG>F(X) применяется к X, а F(Y) применяется к Y
В таком случае пример с x.y.z некорректен — где вторая операция?
На самом деле, "эквивалентности поведения", определённого таким образом, для целей нашей дискуссии недостаточно.
При таком определении легко доказать, что такие две переменные эквивалентны:
int a = 1;
int a1 = a;
Тем не менее, уже интуитивно понятно, что ссылка a1 ближе к переменной a.
А если подходить формально, то из идентичности следует возможность применять несимметричные операции к сравниваемым элементам, и всё ещё иметь эквивалентность поведения.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, DarkGray, Вы писали:
DG>>на вскидку должны быть эквивалентны, но из эквивалентности переменной и ссылки на одном примере не следует, что ссылка и переменная эквиваленты всегда. S>Такого утверждения никто не делал. Зачем вы пытаетесь его опровергать?
некто Sinclair делал: S> Я обещал эквивалентность имён a1 и a2, при условии, что имя a2 определено как ... & a2 = a1.
S>Вам дали пример того, как у одной переменной появляется два имени.
да, пусть будет.
мне лишь не нравится, что ты:
1. употребляешь термин alias для ссылки, не обозначая границ, когда ссылку можно считать alias-ом, а когда нет.
2. отрицаешь, что ссылка — это нечто большее, чем имя. и что она является объектом.
DG>специфицируй тогда эквивалентность каких объектов ты сравнивал и с помощью какой процедуры. а то пальцем тыкать каждый может..
S> Я утверждал, что после такого определения a и a1
соглашусь, если добавить все границы, а именно, что переменная и ссылка должна быть объявлены в одном блоке, и тип ссылки должен быть равен типу самой переменной (с точностью до ссылочности)
ты еще что-то утверждал про a и x.y.z — это утверждение хотелось бы увидеть специфицированным.
и также есть какое-то утверждение, что ссылка является алиасом и на это тоже хочется видеть спецификацию.
S> При таком определении легко доказать, что такие две переменные эквивалентны
если речь идет об эквивалентности переменной и ссылки на эту же переменную, то все твои замечания признаю.
я когда вводил "эквивалентность на наборе операций" чуть другое имел ввиду.
тогда да, нам кроме эквивалентности поведения (что вместо одного элемента мы можем подставлять(использовать) другой), еще необходимо потребовать одинаковость состояния переменной и ссылки в любой момент времени(или более формально, что после любой операции(из заданного набора операций) над переменной или ссылкой состояния должны быть одинаковыми).
Здравствуйте, Sinclair, Вы писали:
S>Ок, без проблем. Тем не менее, количество переменных и количество объектов не совпадают, какие бы мы терминологические ухищрения ни принимали.
Зато в случае использования терминологии стандарта C++ совпадают понятия переменная и имя переменной. Это как раз тот случай когда (имя переменной == переменная) && (переменная != объект), и твое сообщение здесь
Здравствуйте, igna, Вы писали:
I>Здравствуйте, Sinclair, Вы писали:
S>>Ок, без проблем. Тем не менее, количество переменных и количество объектов не совпадают, какие бы мы терминологические ухищрения ни принимали.
I>Зато в случае использования терминологии стандарта C++ совпадают понятия переменная и имя переменной.
Не совпадают. Иначе бы в стандарте так и написали, что это одно и то же. Там же написано что объявление ссылки вводит переменную. Из чего никак не делается вывод что это одно и то же.
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>Не совпадают. Иначе бы в стандарте так и написали, что это одно и то же.
I>С чего бы это? Стандарт не святое писание, там есть ошибки, более того, их там полно. Вон про то, что reference это variable сколько лет не писали.
И сейчас этого не написано. Ты считаешь это ошибкой?
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>И сейчас этого не написано. Ты считаешь это ошибкой?
I>Нет. Кстати, различаешь ли ты точно также понятия тип и имя типа?
различаю
Здравствуйте, igna, Вы писали:
I>Здравствуйте, samius, Вы писали:
S>>различаю
I>Так. А вот в стандарте есть такой пассаж:
I>
I>All function types, function names with external linkage, and variable names with external linkage have a
I>language linkage.
I>Сравни: function types, но function names и variable names. Почему не function type names?
Или ты предлагаешь линковать по именам типов, а не по типам? Так это бред.
не пойму, что тебя смущает в данном пассаже. То что variable names? Так там не просто variable names а variable names with external linkage.
S>Продемонстрируй, как будет выглядеть проверка с помощью консоли компилятора идентичности объектов, на которые ссылаются a и b.
//например, так (а можно еще по AST-у ходить — там будет точнее)
string GetObjectKeyFromCompileError(CompileError error)
{
if (error.SourceLine.Words().Contains("a"))
return"a";
if (error.SourceLine.Words().Contains("b"))
return"b";
return null;
}
DG>>можно. и если она к тому же будет эквивалентной исходной на каком-то подмножестве операций, то это нам позволит утверждать, что C++-программу, которая использует только эти операции, можно напрямую(без введения ВМ) выполнить в БД или с помощью вагонов РЖД. S>Но такая модель не делает поле объекта вагоном.
я плохо понимаю, что в данном случае означает термин "не делает или делает" и почему это важно в данном контексте...
DG>>и каковы границы этого утверждения? S>Оно справедливо в границах ООП в том случае если конструктор прямо или косвенно не записал this куда-нибудь. ООП не рассматривает объекты, которым нельзя отправить сообщение либо проверить идентичность.
но получается, что например, если брать объекты, которые имеют идентичность лишь иногда, то это утверждение не нарушается, отправить сообщения таких объектам можно — надо лишь подождать.
если разбирать твои утверждения и утверждения Синклера, то они опираются на двоичную логику, когда у объекта есть лишь два варианта — идентичность либо есть всегда, либо нет никогда.
и эти утверждения не работают для модели, когда объект рассматривается хотя бы с точки зрения трех состояний: у объекта идентичность есть всегда, у объекта идентичности нет никогда, у объекта идентичность — то есть, то нет.
как пример: когда ты делаешь утверждение "у объекта нет идентичности, и поэтому нельзя отправить ему сообщение", ты подразумеваешь именно вариант, что у объекта нет идентичности никогда, и только для этого варианта утверждение верно.
S>>>Ее можно автоматически переписать и без того что бы считать переменную рантайм объектом ООП.
DG>>покажи чем мы ее при этом считаем, и на основании каких утверждений мы переписываем программу. S>Мы ее ничем не считам. Допустим, что мы можем наблюдать узел AST, который может превратиться в переменную. Но нет никаких оснований считать что узел АСТ имеет какое-то отношение к некой переменной, особенно ввиду того, что сей узел будет заменен на кусок АСТ, представляющий обращение к некому кэшу.
вопрос был: в рамках какой модели делается такое переписывание?
или, например, другими словами: вот есть кусок кода, который это делает — как мы понимаем, что это кусок кода преобразует код верно? монетку подбрасываем? или верим программисту на слово?
DG>>>>потому что в реальных программах — такое поведение встречается с вероятностью 0.001% (условно) DG>>>>соответственно, с вероятностью 99.999% — это ошибка. S>>>посчитать средне-арифметическое значений функции в заданных точках это ошибка с вероятностью 99.999%?
DG>>и где там вызов функции от изменяемой переменной (кроме вызовов от изменяемой переменной цикла, которая пробегает по заданным точкам)? S>Например, вызов функции суммирования агрегата с очередным значением.
использован стандартный паттерн аккумулятор — ничего криминального. при этом на основе промежуточных (изменяемых значений) аккумулятора никаких других расчетов не делается. кроме обновления его самого.
DG>>скажет, что программа требует рефакторинга, и что откомпилированный результат лучше выбросить, если есть возможность. S>Выбросить работающий код потому что он не соответствует паттернам, заложенным в компилятор? Боюсь, что немногие будут пользоваться таким компилятором.
вот возьмем ситуацию, когда компилятор сейчас говорит, что возможен выход за границы массива, и поэтому такую программу лучше выбросить? ты такой программой будешь пользоваться? или ты ее выбросишь (например, перепишешь?)
в чем отличие этой ситуации от приведенной мной ситуации?
с другой стороны, если паттерны можно добавлять, то чем это отличается от тех же классов и статик-типизированных языков?
зы
также паттернов на самом деле счетное число, и они все крутятся вокруг небольшого кол-ва центральных понятий:
состояние, множество, объединение/разница, последовательность, вариант, время, идентификация, отображение, изменение и т.д.
Здравствуйте, samius, Вы писали:
S>Хорошо, пусть будет объект, инициализированный значением этого литерала. Но i — это не объект. Это идентификатор.
Для случая оперирования по значению, это одно и то же.
I>>А употребленное тобой "имя переменной" это в терминах чего было? S>Хорошо, пусть будет "идентификатор".
Имя переменной тоже неплохо, в чем проблема? По определению, переменная в ЯП — это именованный адрес.
Здравствуйте, Lloyd, Вы писали:
L>Да, тип Int32 — неизменяемый. Отсутствие/наличие const тут погоды не делает, т.к. этот модификатор относится не к типу, а к переменной.
DG>>программист это решение принял на основании какой-то информации (а не просто потому что так захотела его левая пятка) DG>>соответственно, я еще раз спрашиваю — какая информация есть у программиста, которой нет у компилятора? S>Собственно так бывает, что сначала левая пятка программиста захотела сделать объект мутабельным, а потом она же захотела сделать его иммутабельным. Может программист покурил чего до того или после и у программиста появились какие-то соображения. Может его на форуме кто надоумил. Компилятору нужна такая информация?
вопрос всё тот же — на основании какой информации человек понял что это правильное решение?
вот если в этой ситуации будет два человека: один говорит надо делать mutable, а другой говорит — нет, надо сделать immutable.
они же этот спор решают приведением доводом на основе какой-то информации, а не монетку бросают.
так какая информация будет использоваться?
S>>Продемонстрируй, как будет выглядеть проверка с помощью консоли компилятора идентичности объектов, на которые ссылаются a и b.
DG>//например, так (а можно еще по AST-у ходить — там будет точнее) DG>
DG> if (error.SourceLine.Words().Contains("a"))
DG> return"a";
DG> ...
DG>
Строчка "b = a'" сломает всю кухню.
И AST тут не поможет, если перед этой строчкой будет "if(rnd.next() < 0.1)".
А раз метод не позволяет отличить объекты, то он не может использоваться в качестве идентичности по определению идентичности.
DG>>>можно. и если она к тому же будет эквивалентной исходной на каком-то подмножестве операций, то это нам позволит утверждать, что C++-программу, которая использует только эти операции, можно напрямую(без введения ВМ) выполнить в БД или с помощью вагонов РЖД. S>>Но такая модель не делает поле объекта вагоном.
DG>я плохо понимаю, что в данном случае означает термин "не делает или делает" и почему это важно в данном контексте...
Это так же важно как и то, является ли поле объектом. "делает или не делает" здесь то же, что и "является или нет".
S>>Оно справедливо в границах ООП в том случае если конструктор прямо или косвенно не записал this куда-нибудь. ООП не рассматривает объекты, которым нельзя отправить сообщение либо проверить идентичность.
DG>но получается, что например, если брать объекты, которые имеют идентичность лишь иногда, то это утверждение не нарушается, отправить сообщения таких объектам можно — надо лишь подождать.
Известная мне ОО парадигма требует идентичности всегда.
DG>если разбирать твои утверждения и утверждения Синклера, то они опираются на двоичную логику, когда у объекта есть лишь два варианта — идентичность либо есть всегда, либо нет никогда. DG>и эти утверждения не работают для модели, когда объект рассматривается хотя бы с точки зрения трех состояний: у объекта идентичность есть всегда, у объекта идентичности нет никогда, у объекта идентичность — то есть, то нет.
Такая модель не является ООП моделью. DG>как пример: когда ты делаешь утверждение "у объекта нет идентичности, и поэтому нельзя отправить ему сообщение", ты подразумеваешь именно вариант, что у объекта нет идентичности никогда, и только для этого варианта утверждение верно.
Хорошо, можно считать что в тот момент, когда невозможно определить идентичнолсть объекта, он не является объектом.
DG>>>покажи чем мы ее при этом считаем, и на основании каких утверждений мы переписываем программу. S>>Мы ее ничем не считам. Допустим, что мы можем наблюдать узел AST, который может превратиться в переменную. Но нет никаких оснований считать что узел АСТ имеет какое-то отношение к некой переменной, особенно ввиду того, что сей узел будет заменен на кусок АСТ, представляющий обращение к некому кэшу.
DG>вопрос был: в рамках какой модели делается такое переписывание? DG>или, например, другими словами: вот есть кусок кода, который это делает — как мы понимаем, что это кусок кода преобразует код верно? монетку подбрасываем? или верим программисту на слово?
Не понимаю, причем здесь кусок кода, преобразующего код? Зачем нам понимать, что он делает?
DG>>>и где там вызов функции от изменяемой переменной (кроме вызовов от изменяемой переменной цикла, которая пробегает по заданным точкам)? S>>Например, вызов функции суммирования агрегата с очередным значением.
DG>использован стандартный паттерн аккумулятор — ничего криминального. при этом на основе промежуточных (изменяемых значений) аккумулятора никаких других расчетов не делается. кроме обновления его самого.
Речь была о том что изменять можно лишь счетчики... Ну да ладно, а почему нельзя делать вычисления на промежуточных значениях?
S>>Выбросить работающий код потому что он не соответствует паттернам, заложенным в компилятор? Боюсь, что немногие будут пользоваться таким компилятором.
DG>вот возьмем ситуацию, когда компилятор сейчас говорит, что возможен выход за границы массива, и поэтому такую программу лучше выбросить? ты такой программой будешь пользоваться? или ты ее выбросишь (например, перепишешь?) DG>в чем отличие этой ситуации от приведенной мной ситуации?
Компилятор и сейчас много чего говорит, чего в принципе не может быть, но он допускает это на основе каких-то заложенных в него паттернов. В частности, он может сказать что переменная может быть не проинициализирована. Из этого не следует что существует вероятность того что она не будет проинициализирована. Да, приходится предпринимать действия, которые нацелены на то, что бы удовлетворить компилятор. Но такие предупреждения вовсе не означают то, что программой невозможно пользоваться. Да, эти предупреждения позволяют обнаруживать ошибки. Но еще раз, они не означают 100% что в программе ошибка.
DG>с другой стороны, если паттерны можно добавлять, то чем это отличается от тех же классов и статик-типизированных языков?
Кто их будет добавлять? Разработчик компилятора? Пользователь компилятора?
DG>зы DG>также паттернов на самом деле счетное число, и они все крутятся вокруг небольшого кол-ва центральных понятий: DG>состояние, множество, объединение/разница, последовательность, вариант, время, идентификация, отображение, изменение и т.д.
Счетное число паттернов — это слишком много для конкретного компилятора, т.к. вопрос принадлежности кода паттерну становится неразрешим за конечное время.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Хорошо, пусть будет объект, инициализированный значением этого литерала. Но i — это не объект. Это идентификатор.
V>Для случая оперирования по значению, это одно и то же.
Возражаю. Идентификатор один, значения разные. Уже это дает повот делать различия.
I>>>А употребленное тобой "имя переменной" это в терминах чего было? S>>Хорошо, пусть будет "идентификатор".
V>Имя переменной тоже неплохо, в чем проблема? По определению, переменная в ЯП — это именованный адрес.
ЯП — это другой уровень. Я говорил в терминах ООП.
DG>>но получается, что например, если брать объекты, которые имеют идентичность лишь иногда, то это утверждение не нарушается, отправить сообщения таких объектам можно — надо лишь подождать. S>Известная мне ОО парадигма требует идентичности всегда.
вы подходите к ООП, как к религии, которая задана как догма.
а это наука, и есть известный алгоритм, как произвольную модель (или теорию) совместить с заданным набором утверждений (в том числе с утверждениями ослабляющий базис исходной модели).
зы
если брать, например, в науке переход к геометрии лобачевского от евклидовой, или к релятивисткой физике из ньютоновской — то они двигались ровно тем же путе: бралось одно из базовых утверждений предыдущей модели(теории) и ослаблялось.
геометрия лобаческового, вообще, была создана как забавные размышления, что будет если считатать, что базисная аксиома параллельные переменные не пересекаются не нужна. и только потом нашли где можно это в реальности использовать.
если послушать тебя с синклером, то выяснится, что и nullable-чисел не должно существовать. из-за того, что математика требует, чтобы числа существовали всегда.
DG>>>но получается, что например, если брать объекты, которые имеют идентичность лишь иногда, то это утверждение не нарушается, отправить сообщения таких объектам можно — надо лишь подождать. S>>Известная мне ОО парадигма требует идентичности всегда.
DG>вы подходите к ООП, как к религии, которая задана как догма.
Я подхожу формально. DG>а это наука, и есть известный алгоритм, как произвольную модель (или теорию) совместить с заданным набором утверждений (в том числе с утверждениями ослабляющий базис исходной модели).
Это за рамками базиса исходной модели, в рамках которой я до сих пор пытался вести беседу.
DG>зы DG>если брать, например, в науке переход к геометрии лобачевского от евклидовой, или к релятивисткой физике из ньютоновской — то они двигались ровно тем же путе: бралось одно из базовых утверждений предыдущей модели(теории) и ослаблялось. DG>геометрия лобаческового, вообще, была создана как забавные размышления, что будет если считатать, что базисная аксиома параллельные переменные не пересекаются не нужна. и только потом нашли где можно это в реальности использовать.
Вот и я об этом. Сначала вы утверждали что я слишком узко понимаю ООП, теперь оказалось что вы его понимаете шире чем оно есть. Если бы вы начали со слов "давайте представим расширенное ООП2, где идентичность не нужна", то возражать было бы нечего.
S>Вот и я об этом. Сначала вы утверждали что я слишком узко понимаю ООП, теперь оказалось что вы его понимаете шире чем оно есть. Если бы вы начали со слов "давайте представим расширенное ООП2, где идентичность не нужна", то возражать было бы нечего.
я хочу от тебя, чтобы ты не просто ссылался на ООП в формате я верю: что с точки зрения ООП — это неверно, а доказал что это неверно.
например, в ООП не вводится понятия времени.
поэтому если ввести формальную функцию идентичности как: идентичность объектов определяется как идентичность состояния объектов в моменты времени t, когда g(t) > 0.
и докажи (или покажи) какому базисному утверждению ООП — это противоречит.
при этом функция идентичности есть — вот она, выше.
Здравствуйте, DarkGray, Вы писали:
S>>Вот и я об этом. Сначала вы утверждали что я слишком узко понимаю ООП, теперь оказалось что вы его понимаете шире чем оно есть. Если бы вы начали со слов "давайте представим расширенное ООП2, где идентичность не нужна", то возражать было бы нечего.
DG>я хочу от тебя, чтобы ты не просто ссылался на ООП в формате я верю: что с точки зрения ООП — это неверно, а доказал что это неверно.
DG>например, в ООП не вводится понятия времени. DG>поэтому если ввести формальную функцию идентичности как: идентичность объектов определяется как идентичность состояния объектов в моменты времени t, когда g(t) > 0.
В момент компиляции мы не знаем даже то, сколько объектов будет создано, не говоря уже о том, какие из ссылок будут указывать на один и тот же объект.
DG>и докажи (или покажи) какому базисному утверждению ООП — это противоречит.
Противоречит тому что идентичность позволяет отличать объекты (безотносительно времени t).
DG>при этом функция идентичности есть — вот она, выше.
Это не идентичность, т.к. она не позволяет отличать объекты.
Давай еще раз, более развернуто
SomeObject *a = GetSomeObject();
SomeObject *b = GetSomeObject();
if (rnd.next() > 0.5)
a = b;
Покажи мне, как будет выглядеть определение того, ссылаются ли переменные на один объект во время компиляции.
if там вообще-то лишний, потому как неизвестно, вернет ли GetSomeObject один и тот же объект, или каждый раз разные, или она будет возвращать один и тот же не более 3х раз... Но пусть if будет хохмы для.
Та функция идентичности, что ты привел, ничего не говорит о идентичности экземпляров SomeObject
Здравствуйте, samius, Вы писали:
S>И все-таки в ООП нет понятия переменной. Но есть идентификаторы объектов, ссылки на объекты.
Полностью неверно. И далее везде по ветке тоже.
Без сущности "переменная" ООП даже не взлетит. Ссылки на объекты, как и на любые другие типы, бывают: прямые и разной степени косвенности. Например, конкретно в дотнете, переменные ссылочного типа — это непрямые ссылки на объекты, а косвенные, т.е. требующие разыменования адреса во время исполнения.
Сорри за приводимый нижее ликбез уровня конца 1-го курса профильной специальности, но прочитаная ветка удивила более, чем полностью...
Рассмотрим value-типы дотнета.
1. статическая переменная — прямая ссылка (абсолютный адрес);
2. член ref-типа — абсолютное смещение относительно адреса объекта;
3. член value-типа — абсолютное смещение относительно адреса объекта. Если адрес объекта известен в compile-time, то смотри 1. (и далее рекурсивно для любых вложений тоже);
4. локальная переменная — абсолютное смещение относительно адреса текущего фрейма стека.
Боксированные value-type ничем не отличаются от экземпляров ref-типов. Отличия есть при размещении их по-значению, ввиду ограничений на наследование, которое позволило в итоге сэкономить и не хранить с value-типами служебную информацию, типа ссылок на дескриптор типа (т.к. он достоверно известен в compile-time).
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>>>Хорошо, пусть будет объект, инициализированный значением этого литерала. Но i — это не объект. Это идентификатор.
V>>>Для случая оперирования по значению, это одно и то же. S>>Возражаю. Идентификатор один, значения разные. Уже это дает повот делать различия.
V>Нет никакого идентификатора в рантайм, это условное обозначение времени компиляции, чтобы тебе было легче отличать один адрес от другого. Но сама сущность "переменная" никуда не девается в рантайм, в отличие от идентификатора. И что ты подразумеваешь под "значения разные"?
Да, неточно выразился. ООП оперирует ссылками на объекты. Но оно и не знает что такое компиляция и время компиляции. Идентификаторы позволяют нам отличать ссылки в ЯП, но это тоже не термин ООП.
Значения — это чуть более обще, чем объект. Пусть будет объект. Не против рассматривать значения примитивных типов в качестве объекта. Но призываю различать идентификатор (i), ссылку (переменную) и значение(объект). V>Конечно, с т.з. ООП, объект может иметь разные состояния, поясни, где ты видишь противоречие? Неужели только из-за того факта, что можно целиком заменить состояние объекта?
Я просто отличаю состояния объекта от состояния переменной. Переменная позволяет целиком заменить объект, на который она ссылается (как ссылка в терминах ООП). Но она и позволяет изменять состояние объекта, сохраняя идентичность объекта. V>Но ведь можно так же не целиком даже для объектов, хранящихся по-значению на стеке (модифицируя только часть полей или вызывая методы, модицифицирующие только часть полей). И точно так же можно целиком изменить состояние объекта, хранящегося на куче, т.е. по неизвестному адресу времени компиляции, поэтому для доступа к которому мы используем переменные ссылочного типа. Абсолютно одинаковые сценарии изменения состояния доступны в обоих случаях.
только ООП не знает что такое куча и стек. И неважно, изменяем ли мы состояние объекта целиком или частично. Когда присваиваем переменной новое значение — она ссылается на новый объект. Если мы вызываем метод объекта, который целиком и полностью меняет свое состояние — то это изменение состояния объекта.
V>Что касается переменных примитивных типов, то стоит таки обратиться к определению ООП, данное Алланом Кеем, но целиком, а не только к первому предложению. Конечно, он вводит понятие "примитивных" типов, ибо где-то должна быть точка отсчетов для построения более сложных композиций из простых. Но экземплярам этих "примитивных" типов никто не мешает быть полноценными объектами. Разница лишь в том, составные это типы или нет, т.е. какова размерность пространства состояний объекта. Согласись, это отличие не означает неприменимости парадигмы ООП к таким примитивным типам. Например, любой объект, имеющий всего одно не ссылочное поле примитивного типа, хоть и является строго говоря составным, но демонстрирует все характеристики точно такого же примитивного типа в плане его пространства состояний. Скажу больше, такие объекты обычно делают для ограничения исходного пространства состояний примитивного типа, т.е. протягивая некую зависимость тип-область_значений в систему типов программы.
С этим согласен.
V>Ну и, возвращаясь к идентификатору. Есть такое понятие identity, это не есть идентификатор. В рамках одной программы identity объекта есть его адрес (даже если предвидеть возражение насчет операций GC по передвижкам объектов, то ведь он подменяет так же все ссылки на него, в т.ч. ref ссылки на внутренние поля объектов, поэтому такая процедура прозрачна для программиста).
Есть такое понятие как object identity. Оно определено достаточно абстрактно. А вот то что в качестве identity в конкретных ООП системах используется storage location — это уже частный случай. Отношение между идентификатором и identity следующее: идентификатор — это имя ссылки, которая ссылается на объекты.
V>А в распределенных средах как identity выступает обычно некий токен из байт или подмножества байт (символов), который опять же нужен для перевода на каждой стороне этого токена в адрес объекта.
Естественно. Только надо отличать, где object identity разрабатываемой системы, а где identity, которой ЯП обеспечивает свое отношение к ООП. Например, в спецификации C# четко сказано, что identity ссылочных типов основывается на storage location, а identity значимых типов — на побитовом соответствии содержимого. Но это не значит, что identity любых систем, написанных на C#, должна быть именно такой.
V>>>Имя переменной тоже неплохо, в чем проблема? По определению, переменная в ЯП — это именованный адрес. S>>ЯП — это другой уровень. Я говорил в терминах ООП.
V>ООП полностью зиждется на процедурном подходе и использует его аппарат для своей реализации. Семантику сущности "переменной" он не изменяет ни разу.
Только в ООП не переменная а ссылка. И не факт что у ссылки есть имя. Переменная — это реализация уровня ЯП понятия ссылка из ООП. V>Да и какая разница, хранится ли объект на куче, на стеке или как поле другого объекта (т.е. непосредственно по значению). Расположение объекта в куче не дает этому сценарию никаких отличий в плане парадигмы ООП, в сравнении с остальными способами расположения объектов. Разница есть, например, для GC в управляемых средах, так же как есть ограничения (например, невозможно получить и сохранить safe-ссылку на поле внутри объекта), но это никакого отношения к самому ООП не имеет.
Да.
Здравствуйте, Sinclair, Вы писали:
S>Вот, например, в следующем коде — ровно одна переменная:
int a1 = 1;
int&a2 = a1;
S>А имён у неё две.
Неверно. Есть одно значение, и две переменных, на него ссылающихся. Если приведенный снипет кода описывает глобальные переменные, то a1 — это непосредственная адресация, a2 — прямая (т.к. ссылка на адрес времени компиляции). Если же это локальные (стековые) переменные, то a1 — это относительная адресация, a2 — разновидность косвенной (относительная и +1 уровень косвенности).
А теперь сделаем такой маленький фокус:
double a1 = 1;
double & a2 = a1;
Ввиду того, что double в опкодах современных процов не может быть адресован непосредственно, даже для случая глобального снипета мы получили прямую адресацию и косвенную. Ввиду того, что непосредственная адресация — это скорее бонус для очень небольшого типа данных, в общем случае я предпочитаю подразумевать этот второй вариант, т.к. он точно такой же для любых составных типов, коих оперируемых обычно на порядки больше.
Поэтому, здесь две косвенные ссылки на одно значение (т.е. на один объект, если уж про ООП речь):
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>И все-таки в ООП нет понятия переменной. Но есть идентификаторы объектов, ссылки на объекты.
V>Полностью неверно. И далее везде по ветке тоже.
Далее по ветке все абсолютно не про ООП в общем виде. Может быть про ООП, но про его частное исполнение.
V>Без сущности "переменная" ООП даже не взлетит. Ссылки на объекты, как и на любые другие типы, бывают: прямые и разной степени косвенности. Например, конкретно в дотнете, переменные ссылочного типа — это непрямые ссылки на объекты, а косвенные, т.е. требующие разыменования адреса во время исполнения.
Переменная — это реализация понятия ссылка из ООП. Само ООП не знает, что такое переменная.
V>Сорри за приводимый нижее ликбез уровня конца 1-го курса профильной специальности, но прочитаная ветка удивила более, чем полностью...
V>Рассмотрим value-типы дотнета. V>1. статическая переменная — прямая ссылка (абсолютный адрес);
Переменная это storage, а не ссылка. В C++ нового стандарта теперь несколько по-другому, но что касается дотнета, то там переменная — это однозначно место в памяти, о чем написано в спеке. V>2. член ref-типа — абсолютное смещение относительно адреса объекта; V>3. член value-типа — абсолютное смещение относительно адреса объекта. Если адрес объекта известен в compile-time, то смотри 1. (и далее рекурсивно для любых вложений тоже); V>4. локальная переменная — абсолютное смещение относительно адреса текущего фрейма стека.
Все-таки я бы различал место и смещение. Смещение задает позицию места относительно места объекта.
V>Боксированные value-type ничем не отличаются от экземпляров ref-типов. Отличия есть при размещении их по-значению, ввиду ограничений на наследование, которое позволило в итоге сэкономить и не хранить с value-типами служебную информацию, типа ссылок на дескриптор типа (т.к. он достоверно известен в compile-time).
V>Рассмотрим value-типы дотнета. V>1. статическая переменная — прямая ссылка (абсолютный адрес); V>2. член ref-типа — абсолютное смещение относительно адреса объекта; V>3. член value-типа — абсолютное смещение относительно адреса объекта. Если адрес объекта известен в compile-time, то смотри 1. (и далее рекурсивно для любых вложений тоже); V>4. локальная переменная — абсолютное смещение относительно адреса текущего фрейма стека.
Спасибо за ликбез.
Можно поинтересоваться, откуда взялись эти замечательные предположения?
Вот, например, "статическая переменная", как известно из букваря, используется в дотнете при помощи инструкции ldsfld/ldsflda. Откуда в MSIL возьмётся абсолютный адрес — непонятно.
Вообще, понятие "адрес" в спецификации дотнета применимо исключительно к unmanaged pointer types, см. секцию 8.9.2.
Понятие "абсолютное смещение" — это, надо полагать, результат вычитания двух поинтеров. Применимо только к unmanaged pointers, unverifiable. То есть, в легальной дотнет-программе понятие смещения использовать нельзя.
Понятие "адреса объекта" в спецификации дотнета не используется. Понятие "адрес текущего фрейма стека" — тоже.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Да, неточно выразился. ООП оперирует ссылками на объекты.
V>Именно, как и процедурный подход ссылками на экземпляры типов. Но ссылки-то разные бывают: http://www.rsdn.ru/forum/philosophy/4505309.1.aspx
Я призываю различать ссылки ЯП от ссылок ООП.
Но даже ссылка ЯП не всегда есть переменная. Так например, согласно новой спеке C++, при объявлении ссылки на статические мемберы объекта переменная не вводится. Ссылка есть, а переменной нет. Считать их одним и тем же — слишком наивно.
V>И отсюда все ниже по ветке с т.з. моего ИМХО лучше бы вырезать с сайта, пока не поздно.
Поздно для чего?
DG>>например, в ООП не вводится понятия времени. S>В ООП время вводится неявно — как последовательность состояний и сообщений. S>Думать, что его нет, не надо.
отлично.
теперь обоснуй почему на основе такого определения времени нельзя использовать вот такую функцию для identity:
идентичность объектов определяется как идентичность состояния объектов в моменты времени t, когда g(t) > 0.
ps
в моделях: последовательность событий, которые как будто время, и время — это совсем разные вещи.
Здравствуйте, samius, Вы писали:
S>Так например, согласно новой спеке C++, при объявлении ссылки на статические мемберы объекта переменная не вводится. Ссылка есть, а переменной нет. Считать их одним и тем же — слишком наивно.
Почему? Надо ясно представлять, что есть ссылка в С++. Это синоним следующего:
T * const variable = someExpr;
Итого, "ссылка" в С++ это переменная константного типа (повторю, не путать с указателями/ссылками НА константный тип), а раз так, т.е. раз модификация значения самой переменной невозможна, то синтаксис можно упростить, например, не пользовать operator->. Зачем это надо? Это дало некую свободу действий по применению шаблонов, где мы можем один и тот же шаблон (т.е. кодогенератор) использовать как для ссылочных типов, так и для оперируемых по-значению. Очень удобно. Без этого техника шаблонов потеряла бы приличную долю своей мощи.
, имеем константное значение адреса, которое известно в compile-time. Выделяется под этот адрес ячейка памяти или нет, семантически неважно, как и в этом выражении:
const int i = 42;
Пока адрес переменной i не берем, то память под переменную не выделяется. Если берем, то выделяется память, хотя используется только там, где нужен именно адрес, а где оперируем значением i непосредственно, все-равно это константа времени компиляции (можешь проверить, хакнув константность переменной через const_cast и записав туда другое значение). Считай это некоей оптимизацией, которая целиком на совести компилятора, ведь происходит много других похожих оптимизаций, с распространением констант времени компиляции, главное что сохраняется семантика.
К чему это я? Просто у ссылок по стандарту нельзя взять адрес, т.е. описанный тобой эффект де-факто присутствует изначально, и его прописали в стандарте, наконец. По мне — так на здоровье, коль исходная семантика не ломается.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Так например, согласно новой спеке C++, при объявлении ссылки на статические мемберы объекта переменная не вводится. Ссылка есть, а переменной нет. Считать их одним и тем же — слишком наивно.
V>Почему?
По спецификации.
V>Надо ясно представлять, что есть ссылка в С++. Это синоним следующего: V>T * const variable = someExpr;
Нет, не синоним. Даже не похоже. Адрес ссылки взять нельзя, обязательно надо инициировать...
V>Не путать с этим: V>T const * variable = someExpr;
V>(Обе декларации комбинаторно порождают 4 варианта)
Я достаточно знаком с C++ что бы не путать такие вещи.
V>Итого, "ссылка" в С++ это переменная константного типа (повторю, не путать с указателями/ссылками НА константный тип), а раз так, т.е. раз модификация значения самой переменной невозможна, то синтаксис можно упростить, например, не пользовать operator->. Зачем это надо? Это дало некую свободу действий по применению шаблонов, где мы можем один и тот же шаблон (т.е. кодогенератор) использовать как для ссылочных типов, так и для оперируемых по-значению. Очень удобно. Без этого техника шаблонов потеряла бы приличную долю своей мощи.
"Итого, "ссылка это переменная" ниоткуда не следует пока.
V>Вернемся к ссылокам на статические члены классов и на глобальные переменные. С учетом вышесказанного и по этой ссылке тоже http://www.rsdn.ru/forum/philosophy/4505309.1.aspx
, имеем константное значение адреса, которое известно в compile-time. Выделяется под этот адрес ячейка памяти или нет, семантически неважно, как и в этом выражении: V>const int i = 42;
V>Пока адрес переменной i не берем, то память под переменную не выделяется. Если берем, то выделяется память, хотя используется только там, где нужен именно адрес, а где оперируем значением i непосредственно, все-равно это константа времени компиляции (можешь проверить, хакнув константность переменной через const_cast и записав туда другое значение). Считай это некоей оптимизацией, которая целиком на совести компилятора, ведь происходит много других похожих оптимизаций, с распространением констант времени компиляции, главное что сохраняется семантика.
Выделяется ли ячейка или нет, неважно. Но семантически важно что мы можем взять адрес этой ячейки.
V>К чему это я? Просто у ссылок по стандарту нельзя взять адрес, т.е. описанный тобой эффект де-факто присутствует изначально, и его прописали в стандарте, наконец. По мне — так на здоровье, коль исходная семантика не ломается.
Все эти рассуждения не приводят к тождеству понятий ссылка и переменная даже в рамках С++.
Более того, устоявшимся и наиболее употребимым является выражение "ссылка на переменную", а не "ссылочная переменная".
Здравствуйте, DarkGray, Вы писали:
DG>теперь обоснуй почему на основе такого определения времени нельзя использовать вот такую функцию для identity: DG>идентичность объектов определяется как идентичность состояния объектов в моменты времени t, когда g(t) > 0.
Потому что на основе такого определения нам не удастся определить, какому объекту мы отдаём сообщения. DG>в моделях: последовательность событий, которые как будто время, и время — это совсем разные вещи.
Да ладно? Ну расскажите мне, что же такое время в моделях.
Я просто компьютерным наукам не обучен, кроме университетского курса математики и физики ничего не знаю.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>отлично. DG>теперь обоснуй почему на основе такого определения времени нельзя использовать вот такую функцию для identity: DG>идентичность объектов определяется как идентичность состояния объектов в моменты времени t, когда g(t) > 0.
Предположим, есть два объекта которые идентичны согласно твоему определению идентичности.
Ответь пожалуйста на три вопроса:
Можно ли в момент времени t+1 послать одному объекту сообщение A, а второму сообщение Б ?
Если да, то каким образом это возможно, т.к. в момент времени t и все предыдущие эти два объекта идентичны ?
Если нет, то нахрена нам нужна такая идентичность ?
Здравствуйте, samius, Вы писали:
S>>>Так например, согласно новой спеке C++, при объявлении ссылки на статические мемберы объекта переменная не вводится. Ссылка есть, а переменной нет. Считать их одним и тем же — слишком наивно.
V>>Почему? S>По спецификации.
Ну коль синтаксис другой, то и спецификации дополнительные нужны понятно.
Это не ответ. Давай еще раз, чем ссылка отличается от любой другой константной переменной?
V>>Надо ясно представлять, что есть ссылка в С++. Это синоним следующего: V>>T * const variable = someExpr; S>Нет, не синоним. Даже не похоже. Адрес ссылки взять нельзя, обязательно надо инициировать...
Адрес нельзя брать по спецификации, иначе бы невозможно было бы использование operator. взамен operator->.
Константы надо обязательно инициализировать при объявлении, итого остается только отличие в operator->.
Насчет инициализации... обязательно инициализировать надо любую константу.
И да, я могу привести пример, где даже ссылки на статические члены всё равно будут переменными (т.е. занимать память):
extern int & i; // заметь, без инициализации
А если ссылка импортируется из DLL, то еще и с доп. переходником, т.е. +1 уровню косвенности. Итого, под эту ссылку будет выделено целых два слота памяти, длиной в машинное слово, вместо ни одной.
Так же как могу привести пример, где ссылка на нестатические члены никогда не будет занимать лишней памяти:
void main() {
int i = 0;
int ref_i = i;
std::cout << ref_i << std::endl;
}
ref_i будет вычислена в compile-time, как и любое вычислимое в compile-time выражение, напр:
const int i = 42;
const int j = i + 1;
S>Выделяется ли ячейка или нет, неважно. Но семантически важно что мы можем взять адрес этой ячейки.
Почему у ссылки отсутствует взятие адреса уже сказал. Можно вернуться к пред. посту.
V>>К чему это я? Просто у ссылок по стандарту нельзя взять адрес, т.е. описанный тобой эффект де-факто присутствует изначально, и его прописали в стандарте, наконец. По мне — так на здоровье, коль исходная семантика не ломается. S>Все эти рассуждения не приводят к тождеству понятий ссылка и переменная даже в рамках С++.
Дык, и константа не равна тождественно обычной переменной. По стандарту, на усмотрение компилятора отводится решение — где и как выделять память под константы и выделать ли вообще. ИМХО, полностью аналогично. Например, адреса констант, требующих память для хранения в сегменте данных (т.н. литералов), компилятор имеет право "склеивать", т.е. вместо десяти одинаковых констант иметь одну, а для обычных переменных — не имеет права. Именно поэтому я вижу аналогичное поведение со случаем константного указателя с точностью до operator-> (т.е. невозможностью взять адрес как раз для того, чтобы обеспечить работоспособность отсутствия небходимости operator->).
S>Более того, устоявшимся и наиболее употребимым является выражение "ссылка на переменную", а не "ссылочная переменная".
Не слышал такого, бо ссылка может быть и на объект в куче.
Есть просто тип данных — ссылка, не надо ничего лишнего гадать, надо понимать, что это константный адрес целевого объекта. Да, иногда этот адрес может быть известным во время компляции, если адрес целевого объекта тоже известен во время компиляции. Именно из-за этого я не вижу противоречий и какого-то особенного случая, отличного от других случаев констант времени компиляции.
Здравствуйте, vdimas, Вы писали:
L>>Да, тип Int32 — неизменяемый. Отсутствие/наличие const тут погоды не делает, т.к. этот модификатор относится не к типу, а к переменной.
V>Дожились...
Нет, простой int вроде.
V>Там в переменной целиком хранится состояние объекта, так что не передергивайте.
Вы путаете понятия разных уровней.
Переменная — понятие конкретного языка программирования, оно служит для идентификации какого-то значения, используемого в прграмме.
Поэтому в каком-то смысле переменная является "ссылкой".
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Почему? S>>По спецификации.
V>Ну коль синтаксис другой, то и спецификации дополнительные нужны понятно. V>Это не ответ. Давай еще раз, чем ссылка отличается от любой другой константной переменной?
Ок, насыплю побольше
* указатель может ссылаться на NULL
* невозможно взять адрес ссылки (уже было, но для полноты списка)
* невозможно объявить ссылку на ссылку как указатель на указатель
* у ссылок нет арифметики (в отличии от константного указателя)
* переменная имеет адрес и размер, а ссылка лишь ссылается на место в памяти, предоставленное некой переменной
* в отличии от указателя, ссылка продлевает время жизни временного объекта
V>>>Надо ясно представлять, что есть ссылка в С++. Это синоним следующего: V>>>T * const variable = someExpr; S>>Нет, не синоним. Даже не похоже. Адрес ссылки взять нельзя, обязательно надо инициировать...
V>Адрес нельзя брать по спецификации, иначе бы невозможно было бы использование operator. взамен operator->.
Неудовлетворительное объяснение. В отличии от указателя (для которого определен оператор ->), ссылка представляет собой псевдоним объекта. Потому, что бы не применялось к ссылке, оно на самом деле применяется к значению, которое лежит в месте памяти, на которое ссылается ссылка. V>Константы надо обязательно инициализировать при объявлении, итого остается только отличие в operator->.
Константный указатель можно проинициализировать NULL-ом.
V>Насчет инициализации... обязательно инициализировать надо любую константу. V>И да, я могу привести пример, где даже ссылки на статические члены всё равно будут переменными (т.е. занимать память): V>extern int & i; // заметь, без инициализации
Еще бы... Но это не объявление ссылки. Это объявление того, что ссылка объявлена в другом месте.
V>А если ссылка импортируется из DLL, то еще и с доп. переходником, т.е. +1 уровню косвенности. Итого, под эту ссылку будет выделено целых два слота памяти, длиной в машинное слово, вместо ни одной.
А это не важно, т.к. взять адреса этих слотов не представляется возможным на уровне языка.
V>Так же как могу привести пример, где ссылка на нестатические члены никогда не будет занимать лишней памяти: V>
V>void main() {
V> int i = 0;
V> int ref_i = i;
V> std::cout << ref_i << std::endl;
V>}
V>
А где ссылка? V>ref_i будет вычислена в compile-time, как и любое вычислимое в compile-time выражение, напр:
Меня на данном уровне обсуждения мало интересуют оптимизации компилятора, который при эквивалентности резульата волен делать что угодно. На уровне языка и i и ref_i — переменные. Я могу взять их адреса и вывести в cout.
S>>Все эти рассуждения не приводят к тождеству понятий ссылка и переменная даже в рамках С++.
V>Дык, и константа не равна тождественно обычной переменной. По стандарту, на усмотрение компилятора отводится решение — где и как выделять память под константы и выделать ли вообще. ИМХО, полностью аналогично. Например, адреса констант, требующих память для хранения в сегменте данных (т.н. литералов), компилятор имеет право "склеивать", т.е. вместо десяти одинаковых констант иметь одну, а для обычных переменных — не имеет права. Именно поэтому я вижу аналогичное поведение со случаем константного указателя с точностью до operator-> (т.е. невозможностью взять адрес как раз для того, чтобы обеспечить работоспособность отсутствия небходимости operator->).
Усмотрение компилятора в отношении ООП меня совершенно не волнуют. Я вообще могу (теоретически) допустить, что компилятор может произвести graph rewriting с редукцией и не оставить ничего, что бы напоминало об исходном коде. Ни узнаваемых структур данных, ни переменных... Это не заставит меня считать что в исходном коде на C++ не стало структур данных и переменных.
S>>Более того, устоявшимся и наиболее употребимым является выражение "ссылка на переменную", а не "ссылочная переменная".
V>Не слышал такого, бо ссылка может быть и на объект в куче.
может. Ссылка она вообще на место. V>Есть просто тип данных — ссылка, не надо ничего лишнего гадать, надо понимать, что это константный адрес целевого объекта. Да, иногда этот адрес может быть известным во время компляции, если адрес целевого объекта тоже известен во время компиляции. Именно из-за этого я не вижу противоречий и какого-то особенного случая, отличного от других случаев констант времени компиляции.
Важное отличие в том, что объявление переменной приводит к созданию storage location для переменной, а объявление ссылки — нет. При этом неважно, выкинет компилятор это storage location, как в случае с ref_i, или нет.
Здравствуйте, samius, Вы писали:
V>>Ну коль синтаксис другой, то и спецификации дополнительные нужны понятно. V>>Это не ответ. Давай еще раз, чем ссылка отличается от любой другой константной переменной? S>Ок, насыплю побольше S>* указатель может ссылаться на NULL
К моему большому сожалению, ссылка тоже может. Еще как.
S>* невозможно взять адрес ссылки (уже было, но для полноты списка) S>* невозможно объявить ссылку на ссылку как указатель на указатель
Это повтор предыдущего (насчет адреса), т.к. иначе таки можно было бы взять адрес ссылки путем взятия ссылки на ссылку и разыменование адреса.
S>* у ссылок нет арифметики (в отличии от константного указателя)
Есть, ведь адрес объекта, на который ссылается аналогичный константный указатель, и лишь об адресной арифметике которого мы можем рассуждать, доступен через операцию & над ссылкой.
S>* переменная имеет адрес и размер, а ссылка лишь ссылается на место в памяти, предоставленное некой переменной
Ссылка имеет размер, конструктор и даже можно организовать ей оператор копирования, дабы пользовать в типах, которые можно хранить в стандартных контейнерах:
int nullTag;
int someValue = 42;
struct A {
int & reference;
A(int & r) : reference(r) {}
A() : reference(nullTag) {}
A & operator=(const A & aa) { new(this)A(aa.reference); return *this; }
bool isNull() const { return &reference == &nullTag; }
};
int main() {
A a;
std::cout << a.isNull() << std::endl;
a = A(someValue);
std::cout << a.isNull() << std::endl;
std::cout << sizeof(A[100]) << std::endl;
std::cout << sizeof(int&) << std::endl;
}
Посмотри на последнюю строку.
S>* в отличии от указателя, ссылка продлевает время жизни временного объекта
Не продлевает ни разу, ссылки на временный объект нельзя хранить.
Наверно ты имел ввиду, что для случая константной ссылки возможно конструирование объекта "по-месту"? Дык, это работает банальный вызов конструктора во время приведения типов. И да, сохранять эту ссылку ни в коем случае нельзя, можно только пользовать в том scope, где этот временный объект, созданный для целей приведения типов, будет жив. Наиболее употребимо как аргумент ф-ий.
V>>Адрес нельзя брать по спецификации, иначе бы невозможно было бы использование operator. взамен operator->. S>Неудовлетворительное объяснение.
Эээ... а попробуй поиграй с синтаксисом "от обратного", оч быстро объяснение перейдет в разряд вполне удовлетворительных.
S>В отличии от указателя (для которого определен оператор ->), ссылка представляет собой псевдоним объекта. Потому, что бы не применялось к ссылке, оно на самом деле применяется к значению, которое лежит в месте памяти, на которое ссылается ссылка.
Если адрес взять нельзя, то стадию разыменования адреса мы пропускаем в любом случае. Иначе просто ничего не сойдется.
V>>Константы надо обязательно инициализировать при объявлении, итого остается только отличие в operator->. S>Константный указатель можно проинициализировать NULL-ом.
Гы:
int * pi = NULL;
int & ri = *pi;
Дарю!
В общем, в сухом остатке имеем отсутствие operator-> и невозможность взять адрес для обеспечения этого.
V>>И да, я могу привести пример, где даже ссылки на статические члены всё равно будут переменными (т.е. занимать память): V>>extern int & i; // заметь, без инициализации S>Еще бы... Но это не объявление ссылки. Это объявление того, что ссылка объявлена в другом месте.
Не... я возражал про память. Без link-time codogeneration память будет выделена, как ни крути.
V>>А если ссылка импортируется из DLL, то еще и с доп. переходником, т.е. +1 уровню косвенности. Итого, под эту ссылку будет выделено целых два слота памяти, длиной в машинное слово, вместо ни одной. S>А это не важно, т.к. взять адреса этих слотов не представляется возможным на уровне языка.
Дык и адреса одной ссылки не возможно. Я новый спек С++ еще не изучал подробно, но ИМХО вводить в стандарт то, что и так выводится из других частей непротиворечивым способом — это же избыточность. Или банальная невнимательность.
V>>Так же как могу привести пример, где ссылка на нестатические члены никогда не будет занимать лишней памяти: V>>
V>>void main() {
V>> int i = 0;
V>> int ref_i = i;
V>> std::cout << ref_i << std::endl;
V>>}
V>>
S>А где ссылка? V>>ref_i будет вычислена в compile-time, как и любое вычислимое в compile-time выражение, напр:
Упс, хотел написать int & ref_i = i;
S>Усмотрение компилятора в отношении ООП меня совершенно не волнуют. Я вообще могу (теоретически) допустить, что компилятор может произвести graph rewriting с редукцией и не оставить ничего, что бы напоминало об исходном коде. Ни узнаваемых структур данных, ни переменных... Это не заставит меня считать что в исходном коде на C++ не стало структур данных и переменных.
Я конкретно про гарантированные compile-time вычисления говорил, не уводи в сторону. Фишка в том, что гарантрованные compile-time вычисления происходят даже в отсутствии оптимизаций. И вычисление констант из той же области видимости — аналогично. Поэтому и привел пример с ref_i (с опиской), что там константа вычислима в compile-time.
S>>>Более того, устоявшимся и наиболее употребимым является выражение "ссылка на переменную", а не "ссылочная переменная". V>>Не слышал такого, бо ссылка может быть и на объект в куче. S>может. Ссылка она вообще на место.
Ну и как тут прикрутить выражение "ссылка на переменную"? Я пользуюсь лишь мемом "ссылка на значение". А связано ли это значение с переменной или нет — дело десятое, напр. адрес значения может быть вычислимым.
S>Важное отличие в том, что объявление переменной приводит к созданию storage location для переменной, а объявление ссылки — нет. При этом неважно, выкинет компилятор это storage location, как в случае с ref_i, или нет.
Ну? Точно так же как объявление T * const ptr прямо по стандарту не обязательно приводит к выделению памяти под переменную, если выражение вычислимо в compile-time. Потому что константа. А если не вычислимо в рантайм, то в обоих случаях память под переменную еще как выделяется. Потому что переменная константного типа. Это такой хитрый ньюанс С++, который следовало бы иметь ввиду, из-за которого оч разное поведение у статических констант и экземплярных, например. Я именно это тебе и толкую, что для аналогичных случаев оба варианта ведут себя полностью аналогично.
V>>Там в переменной целиком хранится состояние объекта, так что не передергивайте.
L>Вы путаете понятия разных уровней.
L>Переменная — понятие конкретного языка программирования, оно служит для идентификации какого-то значения, используемого в прграмме. L>Поэтому в каком-то смысле переменная является "ссылкой".
L>
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Lloyd, Вы писали:
V>>>Термин переменная в ЯП имеет определение. L>>С удовольствием выслушаю ваше определение.
V>Да не мое, чего уж там... V>Меня тогда еще в проекте не было, когда это определение уже было, в Вики дается без изменений оригинала.
Согласно этому определению ссылка не является переменной, т.к. переменной называется область памяти, в которой находится значение. Ссылка лишь ссылается на эту область памяти и только.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>* указатель может ссылаться на NULL
V>К моему большому сожалению, ссылка тоже может. Еще как.
Да, но в теории не должна.
S>>* невозможно взять адрес ссылки (уже было, но для полноты списка) S>>* невозможно объявить ссылку на ссылку как указатель на указатель
V>Это повтор предыдущего (насчет адреса), т.к. иначе таки можно было бы взять адрес ссылки путем взятия ссылки на ссылку и разыменование адреса.
S>>* у ссылок нет арифметики (в отличии от константного указателя)
V>Есть, ведь адрес объекта, на который ссылается аналогичный константный указатель, и лишь об адресной арифметике которого мы можем рассуждать, доступен через операцию & над ссылкой.
Так это адресная арифметика над адресом, который доступен через операцию &, а не над ссылкой.
S>>* переменная имеет адрес и размер, а ссылка лишь ссылается на место в памяти, предоставленное некой переменной
V>Ссылка имеет размер, конструктор и даже можно организовать ей оператор копирования, дабы пользовать в типах, которые можно хранить в стандартных контейнерах: V>
V>Посмотри на последнюю строку.
Если даже ссылка имеет собственный адрес и размер, то значение, на которое ссылается ссылка, хранится не по этому адресу. И этим ссылка отлиается от переменной, на которую она ссылается.
S>>* в отличии от указателя, ссылка продлевает время жизни временного объекта
V>Не продлевает ни разу, ссылки на временный объект нельзя хранить.
объявление ссылки на временный объект продлевает жизнь временного объекта до выхода из скопа, в котором определена ссылка. Это не я придумал. Если какой-то компилятор это не выполняет, моя хата с краю.
V>Наверно ты имел ввиду, что для случая константной ссылки возможно конструирование объекта "по-месту"? Дык, это работает банальный вызов конструктора во время приведения типов. И да, сохранять эту ссылку ни в коем случае нельзя, можно только пользовать в том scope, где этот временный объект, созданный для целей приведения типов, будет жив. Наиболее употребимо как аргумент ф-ий.
Я о временных объектах, которые создает компилятор на стеке при вычислении выражений, включая приведения типов, вызов функций и т.п. При отсутствии ссылки на такой объект, компилятор волен удалить его сразу после того, как тот перестал быть нужен. А ссылка продляет время жизни такого объекта до выхода из скопа.
V>>>Адрес нельзя брать по спецификации, иначе бы невозможно было бы использование operator. взамен operator->. S>>Неудовлетворительное объяснение.
V>Эээ... а попробуй поиграй с синтаксисом "от обратного", оч быстро объяснение перейдет в разряд вполне удовлетворительных.
меня мое объяснение больше устраивает.
S>>В отличии от указателя (для которого определен оператор ->), ссылка представляет собой псевдоним объекта. Потому, что бы не применялось к ссылке, оно на самом деле применяется к значению, которое лежит в месте памяти, на которое ссылается ссылка.
V>Если адрес взять нельзя, то стадию разыменования адреса мы пропускаем в любом случае. Иначе просто ничего не сойдется.
А мы ее итак пропускаем, ведь ссылка — псевдоним объекта, а не указателя на него.
S>>Константный указатель можно проинициализировать NULL-ом.
V>Гы: V>
V>int * pi = NULL;
V>int & ri = *pi;
V>
V>Дарю!
Да не стоит оно того. Здесь ссылка, кстати, проинициализирована не NULL-ом, а тем int-ом, который получается при разыменовании NULL-а.
V>В общем, в сухом остатке имеем отсутствие operator-> и невозможность взять адрес для обеспечения этого.
Ну и область памяти, которая не имеет отношение к значению, если вообще существует.
V>>>extern int & i; // заметь, без инициализации S>>Еще бы... Но это не объявление ссылки. Это объявление того, что ссылка объявлена в другом месте.
V>Не... я возражал про память. Без link-time codogeneration память будет выделена, как ни крути.
V>>>А если ссылка импортируется из DLL, то еще и с доп. переходником, т.е. +1 уровню косвенности. Итого, под эту ссылку будет выделено целых два слота памяти, длиной в машинное слово, вместо ни одной. S>>А это не важно, т.к. взять адреса этих слотов не представляется возможным на уровне языка.
V>Дык и адреса одной ссылки не возможно. Я новый спек С++ еще не изучал подробно, но ИМХО вводить в стандарт то, что и так выводится из других частей непротиворечивым способом — это же избыточность. Или банальная невнимательность.
А это о чем?
V>>>Так же как могу привести пример, где ссылка на нестатические члены никогда не будет занимать лишней памяти: V>>>ref_i будет вычислена в compile-time, как и любое вычислимое в compile-time выражение, напр:
V>Упс, хотел написать int & ref_i = i;
Занимает или не занимает память ссылка — неважно. Важно то, что значение лежит не в той памяти, которую занимает или не занимает ссылка. Значение лежит в памяти переменной (если у той она есть).
S>>Усмотрение компилятора в отношении ООП меня совершенно не волнуют. Я вообще могу (теоретически) допустить, что компилятор может произвести graph rewriting с редукцией и не оставить ничего, что бы напоминало об исходном коде. Ни узнаваемых структур данных, ни переменных... Это не заставит меня считать что в исходном коде на C++ не стало структур данных и переменных.
V>Я конкретно про гарантированные compile-time вычисления говорил, не уводи в сторону. Фишка в том, что гарантрованные compile-time вычисления происходят даже в отсутствии оптимизаций. И вычисление констант из той же области видимости — аналогично. Поэтому и привел пример с ref_i (с опиской), что там константа вычислима в compile-time.
А я говорил о том что результат компиляции может быть несопоставим с терминами языка, потому решать, что есть переменная (в языке) а что нет, на основании бинарного кода не годится.
S>>может. Ссылка она вообще на место.
V>Ну и как тут прикрутить выражение "ссылка на переменную"? Я пользуюсь лишь мемом "ссылка на значение". А связано ли это значение с переменной или нет — дело десятое, напр. адрес значения может быть вычислимым.
Ссылка на переменную оозначает ссылку на значение, хранящееся в переменной.
S>>Важное отличие в том, что объявление переменной приводит к созданию storage location для переменной, а объявление ссылки — нет. При этом неважно, выкинет компилятор это storage location, как в случае с ref_i, или нет.
V>Ну? Точно так же как объявление T * const ptr прямо по стандарту не обязательно приводит к выделению памяти под переменную, если выражение вычислимо в compile-time. Потому что константа. А если не вычислимо в рантайм, то в обоих случаях память под переменную еще как выделяется. Потому что переменная константного типа. Это такой хитрый ньюанс С++, который следовало бы иметь ввиду, из-за которого оч разное поведение у статических констант и экземплярных, например. Я именно это тебе и толкую, что для аналогичных случаев оба варианта ведут себя полностью аналогично.
А я толкую что мы не определяем будет ли то что написано в исходниках функцией по тому заинлайнит компилятор тело или нет. Так же мы не будем определять что является переменной по результату компиляции.
Здравствуйте, vdimas, Вы писали:
L>>С удовольствием выслушаю ваше определение.
V>Да не мое, чего уж там... V>Меня тогда еще в проекте не было, когда это определение уже было, в Вики дается без изменений оригинала.
Если не затруднит, не могли бы вы уточнить, что именно в определении противоречит сказанному мной (Имя никогда не означает "само себя".)?
Здравствуйте, samius, Вы писали:
V>>Меня тогда еще в проекте не было, когда это определение уже было, в Вики дается без изменений оригинала.
S>Согласно этому определению ссылка не является переменной, т.к. переменной называется область памяти, в которой находится значение. Ссылка лишь ссылается на эту область памяти и только.
Я тебе уже показывал, что ссылка занимает вполне конкретную память, могу опять:
struct A {};
struct B { A & a; };
std::cout
<< sizeof(A) << std::endl
<< sizeof(B) << std::endl
<< sizeof(B&) << std::endl;
Но это ссылочный тип, поэтому в сравнении с обычной переменной мы имеем лишние уровни косвенности (тут +1), т.е. сначала идет обращение к переменной-ссылке, извлечение адреса целевого объекта из нее, а затем обращение к целевому объекту по этому адресу. Аналогично использованию переменной ссылочного типа в дотнете.
Здравствуйте, Lloyd, Вы писали:
L>Если не затруднит, не могли бы вы уточнить, что именно в определении противоречит сказанному мной (Имя никогда не означает "само себя".)?
Мне был странен сам наблюдаемый спор вокруг того, что же означает имя переменной, поэтому отослал к определению.
Здравствуйте, Sinclair, Вы писали:
S>Вот, например, "статическая переменная", как известно из букваря, используется в дотнете при помощи инструкции ldsfld/ldsflda. Откуда в MSIL возьмётся абсолютный адрес — непонятно.
MSIL не есть машинный язык. Он слишком высокоуровневый. При любой машинной реализации у статической ячейки будет известный (неизменный, фиксированный) времени выполнения адрес, будь то адрес числовой, как мы привыкли, или даже некий символьный/токен в какой-нить гипотетической ассоциативной машине. С динамическими ячейками это не так, их текущий адрес где-то хранится, а именно в переменных ссылочного типа.
S>Вообще, понятие "адрес" в спецификации дотнета применимо исключительно к unmanaged pointer types, см. секцию 8.9.2.
Правильно, и чтобы получить адрес объекта, его надо запинить, т.к. GC двигает эти объекты. Но из этого следует лишь следующее:
— GC двигает объекты
— чтобы узнать текущий и достоверный адрес объекта, сам объект надо зафиксировать в памяти
— оперирование ссылочными типами прозрачно для программиста
И не более.
И да, unmanaged pointer types все еще обслуживаются опкодами MSIL, такими же, как и managed, если что-то забыл...
S>Понятие "абсолютное смещение" — это, надо полагать, результат вычитания двух поинтеров. Применимо только к unmanaged pointers, unverifiable. То есть, в легальной дотнет-программе понятие смещения использовать нельзя.
Можно, для явного размещения полей, для маршаллинга даже без явного размещения полей. Узнать можно смещение любого поля уже загруженного типа. В любой легальной дотнет-программе.
S>Понятие "адреса объекта" в спецификации дотнета не используется. Понятие "адрес текущего фрейма стека" — тоже.
Ты имел ввиду в шарпе не используется? А в каком высокоуровневом ЯП напрямую фрейм стека доступен? И почему относительно других языков никто не возражает, что доступ к локальным переменным относительный, относительно текущего фрейма стека? Понятие фрейма стека в ходит в описание работы дотнетной байт-машины, так что для нее всё это справедливо. Ну и к тому же в MSIL используется и то и другое, если речь именно о дотнете, а не о шарпе. Чем тебе индекс стековой переменной не адрес?
Здравствуйте, vdimas, Вы писали:
V>MSIL не есть машинный язык. Он слишком высокоуровневый. При любой машинной реализации у статической ячейки будет известный (неизменный, фиксированный) времени выполнения адрес, будь то адрес числовой, как мы привыкли, или даже некий символьный/токен в какой-нить гипотетической ассоциативной машине. С динамическими ячейками это не так, их текущий адрес где-то хранится, а именно в переменных ссылочного типа.
Тем не менее, обсуждать семантику MSIL в терминах некоторой конкретной машинной реализации мне кажется несколько поспешным. И MSIL никак не слишком высокоуровневый. Его уровень — в самый раз. Вся семантика дотнета определена в терминах MSIL. Семантика шарпа определена в ещё более высокоуровневой форме. Там то, что выглядит стековой переменной, запросто может в MSIL превратиться в поле объекта.
V>Можно, для явного размещения полей, для маршаллинга даже без явного размещения полей. Узнать можно смещение любого поля уже загруженного типа. В любой легальной дотнет-программе.
И тем не менее, смещение любого поля в обращении к полю не используется. Если не верите — откройте рефлектором любую дотнет-программу и посмотрите, как устроена команда ldfld.
S>>Понятие "адреса объекта" в спецификации дотнета не используется. Понятие "адрес текущего фрейма стека" — тоже.
V>Ты имел ввиду в шарпе не используется? А в каком высокоуровневом ЯП напрямую фрейм стека доступен? И почему относительно других языков никто не возражает, что доступ к локальным переменным относительный, относительно текущего фрейма стека?
Относительно каких языков? Относительно ассемблера — не возражает.
Относительно даже С уже вопрос о фрейме стека является чисто умозрительным. Никто не мешает оптимизатору разместить локальные переменные, скажем, в регистрах. Именно потому, что доступ к локальным переменным формулируется по именам локальных переменных, безо всяких ссылок на фрейм стека. V>Понятие фрейма стека в ходит в описание работы дотнетной байт-машины, так что для нее всё это справедливо.
Рекомендую (в рамках само-ликбеза) всё же ознакомиться с описанием работы дотнетной байт-машины. Потому что managed stack устроен совершенно не так, как вы пытаетесь это представить, и адреса его ячеек нигде в описании не фигурируют.
V>Ну и к тому же в MSIL используется и то и другое, если речь именно о дотнете, а не о шарпе. Чем тебе индекс стековой переменной не адрес?
Тем, что это никакой не адрес.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
V>>Любая адресация, кроме непосредственной, является "ссылочной", но они всё еще такие разные.
L>Ничего личного, но вы путаете понятия времени исполнения и понятия языка программирования.
Если бы способы адресации были не важны, их бы не проходили на первых курсах профильной специальности. Надо понимать что и как работает, чтобы адекватно использовать любую технологию, не делая заведомо неверных допущений (суть проявляя безалаберность и безответственность). Таки запас по эффективности и ресурсам пока еще не тысячекратный, чтобы позволить себе это.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Согласно этому определению ссылка не является переменной, т.к. переменной называется область памяти, в которой находится значение. Ссылка лишь ссылается на эту область памяти и только.
V>Я тебе уже показывал, что ссылка занимает вполне конкретную память, могу опять:
А я могу показать что память, которую занимает ссылка, не размещает в себе значение, на которое она ссылается.
V>Но это ссылочный тип, поэтому в сравнении с обычной переменной мы имеем лишние уровни косвенности (тут +1), т.е. сначала идет обращение к переменной-ссылке, извлечение адреса целевого объекта из нее, а затем обращение к целевому объекту по этому адресу.
Ну так лишний уровень косвенности и отличает ссылку от переменной, а не сближает их.
V>Аналогично использованию переменной ссылочного типа в дотнете.
ссылочный тип в дотнете семантически ближе к указателю C++, чем к ссылке.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Sinclair, Вы писали:
S>>Вот, например, "статическая переменная", как известно из букваря, используется в дотнете при помощи инструкции ldsfld/ldsflda. Откуда в MSIL возьмётся абсолютный адрес — непонятно.
V>MSIL не есть машинный язык. Он слишком высокоуровневый.
И C++ не есть машинный язк.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, DarkGray, Вы писали:
DG>>теперь обоснуй почему на основе такого определения времени нельзя использовать вот такую функцию для identity: DG>>идентичность объектов определяется как идентичность состояния объектов в моменты времени t, когда g(t) > 0. S>Потому что на основе такого определения нам не удастся определить, какому объекту мы отдаём сообщения.
если нужна формальная сторона: можно доопределить (есть и другие варианты доопределения взависимости от требований задачи) такое поведение как: если объект не получилось идентифицировать с заданной точностью посылка сообщения заканчивается получением ошибки, если сообщение с ответом, и игнорируется, если сообщение без ответа.
зы
напомню, что ООП не требует, чтобы все сообщения обязаны доходить до адресата без потерь.
DG>>в моделях: последовательность событий, которые как будто время, и время — это совсем разные вещи. S>Да ладно? Ну расскажите мне, что же такое время в моделях. S>Я просто компьютерным наукам не обучен, кроме университетского курса математики и физики ничего не знаю.
время — с точки зрения моделирования, это изменения (нет изменений, нет и времени).
раз есть изменение:
то появляется атомарный квант состояния(пространства), которое может измениться
появляется атомарный квант времени, через которое может что-то поменяться.
раз есть несколько(две) плоскостей: состояние(пространство) * время, то они могут быть однородными относительно друг друга, а могут быть и не однородными. при неоднородностях относительно друг друга становится значимым насколько одна плоскость неоднородна относительно себя же в одних и тех же координатах другой плоскости.
изменение требует определение двух функций идентичности: одна специфицирует — как определяется, что объект один и тот же при разных квантах времени, другая специфирует — как определяется, что в объектах произошли изменения.
и это не считая той функции идентичности на которую вы ссылаетесь, которая специфирует лишь как объекты различаются в "пространстве".
из-за того, что время глобально — оно влияет не только на элементы внутри модели, но и на саму модель — формируя ее изменение.
соотственно, для полноты должно быть задано что происходит, если начинает меняться сама модель (например, функции идентичности).
зы
вообще, вы с samius-ом рассматриваете самый просто вариант ООП (и что мне больше всего не нравится, что вы выдаете ее за догму, даже не понимая, какие ограничения вы при этом в нее заложили, который нет в самой концепции ООП)
вы рассматриваете ООП лишь для случая: строго однородное строго атомарное строго непрерывное пространство, условное время (в виде лишь условной последовательности сообщений), есть строго полное знание ("мир" знает всё про всех), все состояния строго однозначные (нет неопределенных состояний)
и соответственно, всех этих ограничений нет в самой модели ООП, а вы их накладываете сами.
отчасти это подтверждается тем, что до сих пор вами так и не приведены полные логичные доказательства, которые бы подтверждали вашу позицию.
ззы
на закуску пример, который показывает как всё непросто хотя бы с той же последовательностью сообщений.
например, часто считается, что события происходят строго одно за другим, но в ЯП — где сообщения(которые в ООП формально асинхронные) положены на вызовы функций (которые формально синхронные) — это не так. там часто ответ может приходить раньше, чем сообщение отправлено.
class Server
{
public void Ping(Action pong)
{
pong();
}
}
class Client
{
static public void Pong()
{
}
static void Main()
{
var server = new Server();
server.Ping(Pong);
}
}
в данном коде, с точки зрения клиента ответ приходит раньше, чем сообщение отправлено.
и при этом от данного поведения не помогают ни локи, ни apartment-модель, что на практике часто забывается, и приводит к трудноуловимым ошибкам.
это я к тому, что даже все ООП-языки, которые существуют, работают в рамках намного более полной ООП-модели, чем та, на которую вы ссылаетесь.
в данном коде, чтобы понять в чем проблема — требуется уже вводит такое понятие как неатомарность операции отправки сообщения.
Здравствуйте, DarkGray, Вы писали:
DG>зы DG>напомню, что ООП не требует, чтобы все сообщения обязаны доходить до адресата без потерь.
Я напомню свой вопрос про машину Тьюринга, оборудованную ненулевым количеством ошибок. Подумайте на досуге, зачем вам нужно такое ООП, в котором сообщения не обязаны доходить до адресата, и будет ли в нём хоть что-то, что не моделируется "обычным" ООП.
DG>>>в моделях: последовательность событий, которые как будто время, и время — это совсем разные вещи. S>>Да ладно? Ну расскажите мне, что же такое время в моделях. S>>Я просто компьютерным наукам не обучен, кроме университетского курса математики и физики ничего не знаю.
DG>время — с точки зрения моделирования, это изменения (нет изменений, нет и времени). DG>раз есть изменение: DG> то появляется атомарный квант состояния(пространства), которое может измениться DG> появляется атомарный квант времени, через которое может что-то поменяться.
DG>раз есть несколько(две) плоскостей: состояние(пространство) * время, то они могут быть однородными относительно друг друга, а могут быть и не однородными. при неоднородностях относительно друг друга становится значимым насколько одна плоскость неоднородна относительно себя же в одних и тех же координатах другой плоскости. DG>изменение требует определение двух функций идентичности: одна специфицирует — как определяется, что объект один и тот же при разных квантах времени, другая специфирует — как определяется, что в объектах произошли изменения.
DG>и это не считая той функции идентичности на которую вы ссылаетесь, которая специфирует лишь как объекты различаются в "пространстве".
DG>из-за того, что время глобально — оно влияет не только на элементы внутри модели, но и на саму модель — формируя ее изменение. DG>соотственно, для полноты должно быть задано что происходит, если начинает меняться сама модель (например, функции идентичности).
Прикольный поток сознания.
1. Вообще, время у нас появляется сразу же, как только появляются понятия "раньше" и "позже". Изменения — это уже следующий уровень.
2. Вы по-прежнему путаете отношение идентичности с отношением эквивалентности.
3. Время совершенно не обязано быть глобальным. "Синхронизация" времени в ООП-модели выполняется только в момент обмена сообщениями. Если два объекта получают сообщения независимо друг от друга, то нельзя определить, кто из них получает что раньше. У каждого из них своё локальное время.
4. Понятие однородности времени и пространства в ООП не имеют никакого смысла, как бы красиво ни звучали эти слова. Особенно однородность относительно друг друга.
DG>вообще, вы с samius-ом рассматриваете самый просто вариант ООП (и что мне больше всего не нравится, что вы выдаете ее за догму, даже не понимая, какие ограничения вы при этом в нее заложили, который нет в самой концепции ООП)
Мы как раз всё понимаем. Это у вас в голове каша — прямо начиная с уровня базовых определений, и продолжая ошибками в элементарной логике.
DG>вы рассматриваете ООП лишь для случая: строго однородное строго атомарное строго непрерывное пространство,
Где вы это увидели? Никакого условия непрерывности пространства в ООП нету, как бы ни вводилось понятие пространства.
Понятие однородности я уже прокомментировал выше. DG>условное время (в виде лишь условной последовательности сообщений), есть строго полное знание ("мир" знает всё про всех), все состояния строго однозначные (нет неопределенных состояний)
Как раз такое время, как я описал — это самое минималистичное определение времени, при котором ООП ещё работает. Поверх него можно вводить более сильные модели времени — например, с глобальным временем или понятием "длительности".
Никакого требования "мира" знать всё про всех нету — это вы придумываете что-то своё.
DG>и соответственно, всех этих ограничений нет в самой модели ООП, а вы их накладываете сами.
Вы не понимаете, что такое "ограничение", и что такое "накладывать". Вся математика строится на том, что изучает минимальные модели. Вот мы вам пытаемся рассказать, что такое минимальное ООП. А вы пытаетесь то выкинуть из него неотъемлемые свойства (думая, что что-то добавляете), то засовываете в него то, без чего ООП работает.
DG>в данном коде, с точки зрения клиента ответ приходит раньше, чем сообщение отправлено.
С чего это вы взяли? Ничего подобного. Вы слишком вольно общаетесь с терминологией. Pong() здесь — никакой не ответ. Если хотите, я вам этот пример разберу поподробнее. DG>это я к тому, что даже все ООП-языки, которые существуют, работают в рамках намного более полной ООП-модели, чем та, на которую вы ссылаетесь.
Конечно. Реальные языки работают со значительно более сложными моделями. Но они получаются из базовой модели ООП.
Для того, чтобы разобрать кашу в голове, нужно разделить всё, что можно разделить. Например, изучить в совершенстве базовую модель. Потом из этих мелких запчастей можно начинать строить более полезные модели.
DG>в данном коде, чтобы понять в чем проблема — требуется уже вводит такое понятие как неатомарность операции отправки сообщения.
Вы хотели сказать "неатомарность операции получения ответа на сообщение". Если что, в вашем примере есть минимум четыре момента времени (это если никаких сообщений более не происходит).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
V>>Обращение по токену относитльно экземпляра. Большая разница? что должен озанчать токен, чтобы всё это работало правильно У ЛЮБОГО экземпляра этого типа? И чем тебе токен не адрес, в случае даже ассоциативной адресации, как в объектах языка JS, например? S>Разница — принципиальна. Понятие адрес в программировании подразумевает определённую арифметику.
Даже в случае ассоциативной адресации? Заметь, числовой арифметики над адресами нет, а относительная ассоциативная адресация еще как есть. Просто другая арифметика. И как-то ты странной иноходью передвигаешься... Когда я говорил о конкретике, ты перешел к абстракциям. Я тебе показываю, что и в абстракциях ничего не меняется, ты пытаешься их ограничивать св-вами некоей конкретики. Давай определяться. Адрес, это в общем случае ключ, служащий для доступа к значению. В упорядоченном множестве адресом может быть номер элемента. В неупорядоченном — некий уникальный токен. Отсюда и есть вид ассоциативной адресации. Прием относительной адресации применим и к ассоциативной, коль правила формирования токена это позволяют, тебе домены интернета в пример. Если адрес — число, то и арифметика числовая, а если символ, то арифметика символьная. Так вот, ввиду того, реализации дотнета известны пока на архитектурах с числовой адресацией, ассоциативные адреса MSIL (namaspace1::namespace2::type::member) переводятся однозначно рантаймом в адреса целевой платформы. А раз соответствие однозначное, то мы можем безопасно рассуждать на любом уровне, как на уровне MSIL, так и на уровне числовых адресов низлежащей системы, рассуждения будут оставаться верными.
S>В частности, возможность оперировать смещениями, что вы и пытаетесь делаеть, когда выдаёте за ликбез свои заблуждения.
Оперирование смещениями это самая естественная операция в любом адресе: USA-Indiana-Sevastopol, Ukraina-Sevastopol. Просто Sevastopol недостаточно.
S>Вы всё же почитайте это описание. Те стеки, которые фигурируют в описании семантики дотнетной байт-машины, это совсем не тот стек, которым вы управляете на ассемблере. А то, как вам преподавали понятие "локальных переменных", пусть остаётся на совести вашего преподавателя.
Читал неоднократно, "совсем не тот стек" — это не определение. Совесть преподавателя чиста, спасибо ему за отсылку к Форту с двумя стеками.
S>Поэтому семантика, которой мы оперируем, не имеет права опираться на потенциально устраняемые вещи типа "смещение относительно фрейма стека".
Имеет. Для исполнения на целевой платформе, повторюсь, должно быть взаимно-однозначное соответствие адреса ячейки в стеке в терминах MSIL (индекс), и адреса реальной воплощенной переменной. Учитывая, что на текущих платформах, для которых существует сегодня дотнет, тоже есть стек, который даже используется весьма похоже, и в плане фреймов высокоуровневых языков тоже, я вообще проблемы не вижу в понимании этого соответствия. Это надо совсем уж что-то себе отвлеченное надумать.... но тогда предлагаю опять же целиком оперировать терминологией и признанными абстракциями, чтобы окончательно не запутаться.
Здравствуйте, DarkGray, Вы писали: DG>и если использовать идеальную модель в которой ничего этого нет, то не получится ни описывать, ни решать проблемы и задачи, которые в действительности происходят в программах и в реальной жизни.
Чушь. Почитайте же хоть что-нибудь из букварей. Никакая, подчёркиваю, никакая реальная машина не является более мощной, чем машина Тьюринга.
DG>позже/раньше -это всего лишь еще одна координата, и при этом ничего дополнительного кроме еще одной координаты не вводится.
Это не координата. Это то единственное понятие времени, которое минимально необходимо в ООП.
DG>раньше значение от 0 до 255 могло находиться в ячейке с координатами от 0 до 1петабайта, DG>а после введения позже/раньше — значение от 0 до 255 может находится в двухмерной сетке: по одной координате — от 0 до 1петабайта, а по другой — от 0 до 1 петатакта)
Такты, как таковые, вводят несколько другое понятие времени, чем необходимое в ООП.
DG>я их не путаю. а знаю, что любое отношение идентичности является таковым только в небольшой локальной модельке, как только модель берется чуть шире оно сразу из отношения идентичности переходит в отношение эквивалентности.
И тем не менее вы пишете бред типа "сравнение состояния объектов вводит ещё одно отношение идентичности".
DG>но вот такой, например, не однозначный вопрос: допустим локальное время с точки зрения каждого объекта непрерывное. DG>но при этом является ли оно таковым же с точки зрения стороннего наблюдателя: как внутри системы? так и снаружи?
Понятие непрерывности ко времени в дискретной системе неприменимо. Разве это не очевидно?
Если нет — погуглите определение термина "непрерывность времени".
DG>в реальности так себя ведет sleep (или гибернейт): программа внутри слипа считает, что у нее время непрерывное, у программы снаружи слипа тоже непрерывное, но при этом с точки зрения второй программы время первой программы разрывное.
В реальности слип себя так не ведёт. Кроме того, мы говорим не про реализацию конкретного слипа, а про математическую модель ООП.
DG>мне непонятно это утверждение. DG>у меня один критерий — можно ли это применить к реальности или нет.
Всё можно применить к реальности. Но если хочется лезть в область теории программирования (а это совершенно необязательно), то нужно привыкнуть к тому, что в модели главное — непротиворечивость. А похожесть терминов на бытовые слова играет второстепенную роль.
Вот, к примеру, не-физики очень обижаются, когда физики говорят им, что переноска тяжестей по горизонтальной поверхности работы не совершает.
DG>вот твой вариант может описать ситуацию с гибернейтом, в чем там проблема? и как ее решать? или не может? если не может — значит в топку.
Конечно же может. А в чём там проблема?
DG>есть же, конечно. как только ты начинаешь утверждать, что сообщения гарантированно доходят — это вводит требование, что пространство непрерывно.
Опять каша в голове. Пространство — это категория взаиморасположенности и протяжённости.
Ни о чём подобном модель ООП не берётся рассуждать.
Гарантия доставки не имеет никакого отношения к пространству. DG>что опять же не умеет описывать поведение такой реальной штуки, как работу тонкого клиента в браузере в мобильнике.
Очередной бред. Оставим гон про разрывность пространства, сосредоточимся на осмысленном разговоре о негарантии доставки.
Очевидно, что модель с гарантией доставки легко может эмулировать модель без гарантии — достаточно ввести посредника, который будет либо доставлять сообщения, либо дропать/отказывать, в зависимости от своего состояния.
Обратное смоделировать в общем случае невозможно.
DG>что значит еще работает?
Значит, что если убрать понятия "раньше" и "позже", то ООП перестанет работать.
DG>если этого нет, то какая модель это описывает? вот, например, в аналогом компьютере — нет никакой последовательности сообщений. при этом его работу какая модель описывает? и в чем ее отличие от Канонической Модели ООП с большой буквы?
Его работу описывает какая-то вычислительная математика. ООП будет из рук вон плохо моделировать аналоговый компьютер. А вы этого не знали?
DG>как только ты ввел требование, что есть единая функция идентичности в любой момент времени, ты потребовал — что мы все объекты мира можем перечислить в любой момент времени, что и означает, что "мир" знает про все объекты.
Нет. Мне достаточно знать, что для любого конечного подможества множества всех объектов функция идентичности ведёт себя нужным мне образом. Я же говорю — тренируйте формальную логику.
DG>например, когда арифметика говорит, что 1 + 1 = 2, она накладывает ограничение, что эти единицы есть независимы друг от друга, являются однородными объектами и т.д. если же мы хотим в реальности сложить 1 программиста с 1 автобусом будут требоваться более сложные модели(теории), чем арифметика. например, теория множеств и категорий
Почитайте же букварь!
Арифметика строится на теории множеств, а не наоборот! Арифметика сложнее теории множеств!
DG>ООП есть универсальный базис для программирования, так же как теория множеств в математике.
Нет. Никто этого не обещал. Универсальным базисом для программирования являются функции Чёрча или Машина Тьюринга.
А ООП — это всего лишь модель, удобная для описания каких-то специфических программ.
DG>в конечном итоге, всё сводится к этому базису: есть что-то (то, что в ООП определяется как объект), это как-то можно пощупать(то, что в ООП называется состоянием), оно как-то взаимодействуют (то, что в ООП называется сообщениями).
DG>а дальше на этом базисе рассматриваются более слабые или более сильные модели. с введением тех или иных наборов ограничений, и получений следствий.
DG>при чем вики говорит про тоже самое: там нет, например, никакого требования идентичности.
Просто вики, на которую вы ссылаетесь, не является формальной моделью ООП. Там написан текст для среднестатистического читателя.
DG>давай разбирать. в итоге, конечно, всё сведется к тому, что на данном примере накручено две ООП-модели. для той, которая считает, что Ping — это полноценное сообщение, Pong не будет ответом, а для той — которая считает, что Ping это есть половинка запроса Ping/Pong — будет ответом. DG>но разобраться пожалуйста — это всегда интересно.
Синхронная посылка сообщения в ООП — это два события: "отправить сообщение" и "получить ответ". Эти события не обязаны идти "подряд", т.е. между ними могут происходить и другие события.
В примере есть две посылки сообщения. Последовательность событий такова:
1. отправить Пинг
2. отправить Понг
3. получить ответ на Понг
4. получить ответ на Пинг
В нашем случае ответы имеют тип void, тем не менее, это ответы (мы дожидаемся их прихода)
Если хочется выбрать асинхронную модель, то набор событий станет несколько другим:
1. отправить Пинг
2. получить Пинг
3. отправить Понг
4. получить Понг
Из-за асинхронности наша модель времени стала несколько слабее. Тем не менее, 4е событие не может произойти раньше первого.
Какую бы модель мы ни выбрали, ответ не может прийти раньше запроса — это бы нарушило принцип причинности.
DG>другими словами полная цепочка получается следующей: сложная модель (например, та, которая описывает поведение хренек для которых нет полной идентичности) получена из базовой модели (в данном случае, ООП)
DG>это с точки зрения модели, когда каждое вызов функции есть отдельное сообщение. DG>так же, как я же уже выше говорил, здесь есть и вторая модель, когда только вместе ping/pong образуют одну пару запрос/ответ.
Я же говорю: в модели главное — непротиворечивость. Если в вашей модели ответ приходит раньше запроса, то вы где-то ошиблись. DG>и вторая модель более лаконично описывает поведение данного кода, но требует более сложных понятий — в данном случае, требуется понятие не атомарности запроса (уже в процессе выполнения запроса мы можем получить ответ)
Вторая модель плоха ещё и тем, что она непригодна для описания примеров, хоть чуть-чуть отличающихся от приведённого:
class Server
{
public int Ping(Action<int> pong)
{
return pong();
}
}
class Client
{
static public int Pong()
{
return 42;
}
static void Main()
{
var server = new Server();
var r = server.Ping(Pong);
}
}
Кто здесь запрос, а кто ответ?
class Server
{
public Server(Action<int> pong)
{
_pong = pong;
}
public int Ping()
{
return pong();
}
}
class Client
{
static public int Pong()
{
return 42;
}
static void Main()
{
var server = new Server(Pong);
var r = server.Ping();
}
}
А здесь?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vdimas, Вы писали: V>Даже в случае ассоциативной адресации? Заметь, числовой арифметики над адресами нет, а относительная ассоциативная адресация еще как есть.
Конечно. По традиции, то, что поддерживает только операцию dereference, называется ссылкой.
Просто другая арифметика. И как-то ты странной иноходью передвигаешься... Когда я говорил о конкретике, ты перешел к абстракциям. Я тебе показываю, что и в абстракциях ничего не меняется, ты пытаешься их ограничивать св-вами некоей конкретики. Давай определяться. Адрес, это в общем случае ключ, служащий для доступа к значению. В упорядоченном множестве адресом может быть номер элемента. В неупорядоченном — некий уникальный токен. Отсюда и есть вид ассоциативной адресации. Прием относительной адресации применим и к ассоциативной, коль правила формирования токена это позволяют, тебе домены интернета в пример. Если адрес — число, то и арифметика числовая, а если символ, то арифметика символьная. Так вот, ввиду того, реализации дотнета известны пока на архитектурах с числовой адресацией, ассоциативные адреса MSIL (namaspace1::namespace2::type::member) переводятся однозначно рантаймом в адреса целевой платформы. А раз соответствие однозначное, то мы можем безопасно рассуждать на любом уровне, как на уровне MSIL, так и на уровне числовых адресов низлежащей системы, рассуждения будут оставаться верными.
Нет. Вы делаете логический "перепрыг". Из однозначности соответствия никак не следует то, что арифметика тоже обладает однозначным соответствием.
Поясню на пальцах: пусть у вас будет два исходных "адреса", A1 и A2. Они отображаются в целевые адреса, A1' и A2', функцией M: A1' = F(A1).
Теперь вы почему-то предполагаете, что если у нас есть операция, определённая над одним пространством адресов, то будет и соответствующая ей операция в другом пространстве.
Проверим:
Offset' = A2' — A1'.
Из этого должно следовать, что
1. есть операция "-", определённая на адресах A2 и A1:
A2 — A1 = Offset.
2. Offset' = M(Offset)
А теперь попробуйте найти мне спецификацию этой "операции", которая применима к Metadata Token, в ECMA.
V>Оперирование смещениями это самая естественная операция в любом адресе: USA-Indiana-Sevastopol, Ukraina-Sevastopol. Просто Sevastopol недостаточно.
Только в том, который поддерживает арифметику. Учите букварь.
V>Имеет. Для исполнения на целевой платформе, повторюсь, должно быть взаимно-однозначное соответствие адреса ячейки в стеке в терминах MSIL (индекс), и адреса реальной воплощенной переменной.
Нет. Это вы придумываете. Исполнять дотнет можно и на платформе, где адреса не подразумевают понятия смещения. Просто потому, что "смещения", которые вам так нравятся, нигде в спецификации не используются.
V>Учитывая, что на текущих платформах, для которых существует сегодня дотнет, тоже есть стек, который даже используется весьма похоже, и в плане фреймов высокоуровневых языков тоже, я вообще проблемы не вижу в понимании этого соответствия. Это надо совсем уж что-то себе отвлеченное надумать.... но тогда предлагаю опять же целиком оперировать терминологией и признанными абстракциями, чтобы окончательно не запутаться.
Согласен. Если хочется поговорить о переменных в дотнете, будьте любезны оперировать терминологией ECMA-335. А рассуждения про адреса и фреймы стеков оставьте для тех платформ, где они являются терминологией и признанными абстракциями (например, для x86-ассемблера)
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Поясню на пальцах: пусть у вас будет два исходных "адреса", A1 и A2. Они отображаются в целевые адреса, A1' и A2', функцией M: A1' = F(A1). S>Теперь вы почему-то предполагаете, что если у нас есть операция, определённая над одним пространством адресов, то будет и соответствующая ей операция в другом пространстве. S>Проверим: S>Offset' = A2' — A1'. S>Из этого должно следовать, что S>1. есть операция "-", определённая на адресах A2 и A1: S>A2 — A1 = Offset. S>2. Offset' = M(Offset) S>А теперь попробуйте найти мне спецификацию этой "операции", которая применима к Metadata Token, в ECMA.
Ну дык проще простого. Если ты имел ввиду индексы переменных, то напиши код получения адресов стековых переменных в терминах MSIL и возьми разницу. Посмотри на полученный код. Вот тебе способ описать в одних терминах другие.
V>>Оперирование смещениями это самая естественная операция в любом адресе: USA-Indiana-Sevastopol, Ukraina-Sevastopol. Просто Sevastopol недостаточно. S>Только в том, который поддерживает арифметику. Учите букварь.
Ох уж эти мне "учителЯ" доморощенные, путающиеся в трех соснах.
V>>Имеет. Для исполнения на целевой платформе, повторюсь, должно быть взаимно-однозначное соответствие адреса ячейки в стеке в терминах MSIL (индекс), и адреса реальной воплощенной переменной. S>Нет. Это вы придумываете. Исполнять дотнет можно и на платформе, где адреса не подразумевают понятия смещения.
Нельзя, и если попробуешь хотя бы на пальцах нарисовать, оч быстро поймешь, почему. Даже если у нас ассоциативная иерархическая память (для поддержки ООП), тебе для доступа к мемберу объекта нужен будет сам объект, т.е. база, в терминологии адресации.
S>Просто потому, что "смещения", которые вам так нравятся, нигде в спецификации не используются.
Используется индекс элемента, какая фиг разница. Фрейм локальных переменных дотнета — это множество объектов, доступ к которым мы ведем по индексу. Имея только индекс элемента, но не имея базы — самого текущего фрейма, ты не сможешь получить переменную. В общем, ф-ия доступа к переменной — она от двух аргументов, фрейма и индекса:
el = F(frame, index);
А теперь можно смело goto букварь... а домашнее задание будет: что это за вид адресации?
Здравствуйте, samius, Вы писали:
V>>Я тебе уже показывал, что ссылка занимает вполне конкретную память, могу опять: S>А я могу показать что память, которую занимает ссылка, не размещает в себе значение, на которое она ссылается.
А указатель размещает?
V>>Но это ссылочный тип, поэтому в сравнении с обычной переменной мы имеем лишние уровни косвенности (тут +1), т.е. сначала идет обращение к переменной-ссылке, извлечение адреса целевого объекта из нее, а затем обращение к целевому объекту по этому адресу. S>Ну так лишний уровень косвенности и отличает ссылку от переменной, а не сближает их.
Правильно, прямо как указатель! Не забыл еще исходное утверждение?
V>>Аналогично использованию переменной ссылочного типа в дотнете. S>ссылочный тип в дотнете семантически ближе к указателю C++, чем к ссылке.
Смотря какой ссылочный. Если тот, который ref в аргументах, то это точная аналогия ссылки С++. В любом случае, для ссылочного типа главное, что он хранит не значение, а его адрес. Даже если это адрес времени компиляции, т.е. константа.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Sinclair, Вы писали:
S>>Поясню на пальцах: пусть у вас будет два исходных "адреса", A1 и A2. Они отображаются в целевые адреса, A1' и A2', функцией M: A1' = F(A1). S>>Теперь вы почему-то предполагаете, что если у нас есть операция, определённая над одним пространством адресов, то будет и соответствующая ей операция в другом пространстве. S>>Проверим: S>>Offset' = A2' — A1'. S>>Из этого должно следовать, что S>>1. есть операция "-", определённая на адресах A2 и A1: S>>A2 — A1 = Offset. S>>2. Offset' = M(Offset) S>>А теперь попробуйте найти мне спецификацию этой "операции", которая применима к Metadata Token, в ECMA.
V>Ну дык проще простого. Если ты имел ввиду индексы переменных, то напиши код получения адресов стековых переменных в терминах MSIL и возьми разницу. Посмотри на полученный код. Вот тебе способ описать в одних терминах другие.
Нет в IL способов определить "адрес стековых переменных". Переменные в стеке il могут оказать вовсе не в стеке в сгенерированном коде.
S>>Просто потому, что "смещения", которые вам так нравятся, нигде в спецификации не используются.
V>Используется индекс элемента, какая фиг разница. Фрейм локальных переменных дотнета — это множество объектов, доступ к которым мы ведем по индексу. Имея только индекс элемента, но не имея базы — самого текущего фрейма, ты не сможешь получить переменную. В общем, ф-ия доступа к переменной — она от двух аргументов, фрейма и индекса: V>el = F(frame, index);
Хрень ты написал. Переменная в стеке в IL может превратиться в обращение к регистру процессора. Именно поэтому IL не оперирует понятием адреса, чтобы был больший простор для генерируемого кода. Введение адресов и смещений в язык напрочь убивает возможные оптимизации и типобезопасность.
Ты это еще не осознал? Выгоднее иметь язык, который не оперирует адресами.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>Ну дык проще простого. Если ты имел ввиду индексы переменных, то напиши код получения адресов стековых переменных в терминах MSIL и возьми разницу. Посмотри на полученный код. Вот тебе способ описать в одних терминах другие. G>>Нет в IL способов определить "адрес стековых переменных". Переменные в стеке il могут оказать вовсе не в стеке в сгенерированном коде.
V>Вы тут сговорились, что ле? V>
V>using System;
V>namespace ConsoleApplication2 {
V> struct Probe { public int i; }
V> class Program {
V> unsafe static void Main(string[] args) {
V> var safeVar = new Probe();
V> Console.WriteLine(safeVar.i);
V> Probe* unsafeVar = &safeVar;
V> Console.WriteLine(unsafeVar->i);
V> }
V> }
V>}
V>
V>Для обоих случаев используются одни и те же опкоды (я уже упоминал этот ключевой момент сообщением выше): V>
Так это не не адрес переменной, который фрейм+смещение, а адрес некоторого объекта, который очевидно есть, так как объект размещен в памяти. При этом ссылка != указатель.
V>Понятие safe/unsafe работает ВНЕ байт-машины, а именно: обслуживается верификатором. И нужно исключительно для типобезопасности в угоду программиста и для корректной работы GC. О наличии GC, заметь, байт-машина даже не подозревает, это внешний, по отношению к ней, механизм.
Не понял фразы. Байт-машины нету вообще, есть абстракция, эта абстракция описывается ecma-335, в нем есть GC и верификация. Для указателей есть определенные правила, позволяющие им работать к таком окружении коректно.
И вообще, указатель это адрес, но нельзя взять любой адрес и превратить его в указатель. Поэтому и адресной арифметики как таковой нету.
V>ldloca.s index
V>Загружает в стек вычислений адрес локальной переменной с индексом index (короткая форма).
V>Определение семантики этой операции байт машины оперирует понятием "локальная переменная", считая его известным читателю, и оперирует термином "адрес", так же считая сей термин общеизвестным.
Последнее неверно, оно просто не соотвествует тому что в Ecma написано.
V>А вы мне оба пытаетесь внушить, что нет ни локального фрейма памяти, ни адреса внутри фрейма. Смешно. Кстати, почему эти фреймы памяти образуют именно структуру "стек" во время работы программы, т.е. сущность с дисциплиной LIFO, но никак иначе — оставлю для самостоятельной медитации, это не сложно.
Во время работы программы все это есть, но этим не надо и вообще говоря нельзя оперировать в терминах .NET. Ты не можешь получить фрейм стека и вычислить адрес переменной. Стековые переменные "адресуются" по индексу и все.
V>Ну и то, что адрес МОЖЕТ располагаться не на стеке — подобные половые трудности предлагаю держать при себе, они не интересуют программиста. Я писал долго для микроконтроллеров, где стек сильно ограничен, и там компилятор тоже использовал области глобальной памяти для размещения локальных переменных, т.е. эмулировал еще один стек, а именно стек данных, ввиду недостаточной глубины имеющегося, используемого только под стек возвратов. Но эти моменты программисту должны быть абсолютно до фени. Кстати, программист в любом случае должен считать, что стек возвратов и стек данных — это разные стеки, по крайней мере все компиляторы высокоуровневых ЯП обеспечивают такую семантику, даже если у целевого процессора всего один стек. Это прозрачно для программиста.
V>>>Используется индекс элемента, какая фиг разница. Фрейм локальных переменных дотнета — это множество объектов, доступ к которым мы ведем по индексу. Имея только индекс элемента, но не имея базы — самого текущего фрейма, ты не сможешь получить переменную. В общем, ф-ия доступа к переменной — она от двух аргументов, фрейма и индекса: V>>>el = F(frame, index);
G>>Хрень ты написал. Переменная в стеке в IL может превратиться в обращение к регистру процессора. Именно поэтому IL не оперирует понятием адреса, чтобы был больший простор для генерируемого кода.
V>Ты бы что ле освежил свои познания IL, а то действительно хрень выходит. Можешь начать с приведенной ссылки, там слева все остальные опкоды. Мало-ли во что JIT превратит твою программу? С чего ты взял, что обязательно в регистр процессора? А если он вообще спекулятивно произведет расчеты и вернет сразу результат-константу в результате инлайнинга и распространения констант после этого инлайнинга? Занимаешься гаданиями, короче, не существенными для дела.
Из-за флеймов на форуме я перечитываю excma-334 и 335 не реже раза в месяц, и тебе советую.
Как переменная стека определяется в ассемблерном коде: чаще всего фрейм стека хранится в регистре ebp и переменные в стеке являются смещениями, вроде ebp+4. Чтобы взять адрес объект в куче надо выполнить mov eax,[ebp+4], а чтобы обратиться к самому объекту надо еще раз обратиться по адресу, полученному в eax.
В терминах il операция вроде mov eax,[ebp+4] записывается как ldloc, причем JIT может решить что нет смысла выполнять много раз такую операция и положить локальную переменную в регистр.
То что ты написал уже выполняется после вычисления адреса переменной, и для получения адреса по ссылке не нужен фрейм стека.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Я тебе уже показывал, что ссылка занимает вполне конкретную память, могу опять: S>>А я могу показать что память, которую занимает ссылка, не размещает в себе значение, на которое она ссылается.
V>А указатель размещает?
Указатель размещает значение, т.к. значением указателя является не то значение, на которое он ссылается, а именно адрес того значения.
V>>>Но это ссылочный тип, поэтому в сравнении с обычной переменной мы имеем лишние уровни косвенности (тут +1), т.е. сначала идет обращение к переменной-ссылке, извлечение адреса целевого объекта из нее, а затем обращение к целевому объекту по этому адресу. S>>Ну так лишний уровень косвенности и отличает ссылку от переменной, а не сближает их.
V>Правильно, прямо как указатель! Не забыл еще исходное утверждение?
Прямо как указатель, но это не приближает ссылку к переменной-указателю.
S>>ссылочный тип в дотнете семантически ближе к указателю C++, чем к ссылке.
V>Смотря какой ссылочный. Если тот, который ref в аргументах, то это точная аналогия ссылки С++.
Ссылочный тип в дотнете ровно один — тот, чьи экземпляры размещаются в управляемой куче. ref-же является чисто модификатором способа передачи аргумента и не образует нового типа в терминах системы типов дотнета.
V>В любом случае, для ссылочного типа главное, что он хранит не значение, а его адрес. Даже если это адрес времени компиляции, т.е. константа.
В общем, ссылочный тип в C++ был бы тождественнен ref-параметрам дотнета, если бы ECMA не позволяла использовать copy-in/copy-out механизм для ref/out параметров
Здравствуйте, DarkGray, Вы писали:
DG>ты же отвечаешь про stack, как про конкретную штуку из реализации конкретных ЯП, которые в данном случае вообще никакого отношения к дискуссии не имеют.
Сказать честно, я и тут не вижу разницы. Особенно потому что юзал одни и те же ЯП на процах которые имеют стек и на тех, которые не имеют, т.е. комплятор эмулирует стек. "Конкретная штука" любого высокоуровневого ЯП так же оперирует лишь абстракцией, не давая прямого доступа к подробностям фреймов стека. И правильно, процессор все-равно, даже если имеет специальный индексный/базовый регистр для нужд стека, предоставляет максимум нетипизированные области байт, как и в других своих возможностях, т.е. только язык+компилятор дают нам работать с типизированными переменными в локальных областях, на себя тонкости реализации своих абстракций. Чем локальные переменные дотнета "абстрактнее" локальных переменных Паскаля, наприме, в упор не понимаю. В Паскале даже чуть покруче из-за фичи объединения фреймов.
Ну и создание фреймов стека исторически было на совести компиляторов, это была сугубо прикладная штуковина, выполняемая низкоуровневыми инструкциями. Например, после устаканивания правил для выскокоуровневых языков для x86-й платформы, потом дополнили ее инструкцией enter. Могли бы и не дополнять, просто 4 байта кода теперь экономят на каждой высокоуровневой процедуре/ф-ии.
Здравствуйте, samius, Вы писали:
V>>Не продлевает ни разу, ссылки на временный объект нельзя хранить. S>объявление ссылки на временный объект продлевает жизнь временного объекта до выхода из скопа, в котором определена ссылка. Это не я придумал. Если какой-то компилятор это не выполняет, моя хата с краю.
Есть разные виды временных объектов. Если речь про r-value, то на него нельзя получить обычную ссылку, только константную, и я об этом уже говорил. Если же мы получаем ссылку на l-value, то мы заведомо имеем дело не со значением, а со ссылкой, поэтому ничего не продлеваем, а просто запоминаем/делаем копию ссылки.
S>Я о временных объектах, которые создает компилятор на стеке при вычислении выражений, включая приведения типов, вызов функций и т.п. При отсутствии ссылки на такой объект, компилятор волен удалить его сразу после того, как тот перестал быть нужен. А ссылка продляет время жизни такого объекта до выхода из скопа.
Опять же, речь о константной ссылке, и она должна быть стековой переменной. Т.е. это не работает, если мы инициализируем ссылкой некий мембер-ссылку.
V>>Если адрес взять нельзя, то стадию разыменования адреса мы пропускаем в любом случае. Иначе просто ничего не сойдется. S>А мы ее итак пропускаем, ведь ссылка — псевдоним объекта, а не указателя на него.
Это всего-лишь означает, что этот адрес компилятор разыменовывает за тебя.
V>>Гы: V>>
V>>int * pi = NULL;
V>>int & ri = *pi;
V>>
V>>Дарю! S>Да не стоит оно того. Здесь ссылка, кстати, проинициализирована не NULL-ом, а тем int-ом, который получается при разыменовании NULL-а.
Нет, именно NULL-ом. *pi не создает копии значения, а приводим напрямую к ссылочному типу. Кстати, этот момент когда-то напрягал в С, бо семантика ссылок в таких точно местах в С используется, а самих ссылок в языке нет. Обрати внимание, выражению *p ты можешь присвоить значение (если в "p" валидный адрес), т.е. тип этого выражения фактически int&, оно же l-value. То, что этот адрес невалидный в этом снипетте никак не влияет на типы.
V>>В общем, в сухом остатке имеем отсутствие operator-> и невозможность взять адрес для обеспечения этого. S>Ну и область памяти, которая не имеет отношение к значению, если вообще существует.
Дык, точно так же как и в случае любых других констант: не факт что занимает память когда в статике или локально, но обязательно занимает, когда является экземплярным мембером. Такие вот в С++ константы.
V>>>>Так же как могу привести пример, где ссылка на нестатические члены никогда не будет занимать лишней памяти: V>>>>ref_i будет вычислена в compile-time, как и любое вычислимое в compile-time выражение, напр:
V>>Упс, хотел написать int & ref_i = i; S>Занимает или не занимает память ссылка — неважно. Важно то, что значение лежит не в той памяти, которую занимает или не занимает ссылка. Значение лежит в памяти переменной (если у той она есть).
Значение может и на куче лежать, какие проблемы? Только это уже будет не константа времени компиляции, а константа времени выполнения. В любом случае, то, что ты написал, верно и для констант-указателей.
S>>>Усмотрение компилятора в отношении ООП меня совершенно не волнуют. Я вообще могу (теоретически) допустить, что компилятор может произвести graph rewriting с редукцией и не оставить ничего, что бы напоминало об исходном коде. Ни узнаваемых структур данных, ни переменных... Это не заставит меня считать что в исходном коде на C++ не стало структур данных и переменных.
V>>Я конкретно про гарантированные compile-time вычисления говорил, не уводи в сторону. Фишка в том, что гарантрованные compile-time вычисления происходят даже в отсутствии оптимизаций. И вычисление констант из той же области видимости — аналогично. Поэтому и привел пример с ref_i (с опиской), что там константа вычислима в compile-time. S>А я говорил о том что результат компиляции может быть несопоставим с терминами языка, потому решать, что есть переменная (в языке) а что нет, на основании бинарного кода не годится.
Для С/С++ это слишком вольное допущение. Он получил популярность именно из-за возможности обеспечить фактически побитовую детерминированность результата. Т.е. абсолютно любой комплятор С++ имеет и специфицированное ABI, и возможность управлять кодогенерацией. А абстрактный стандарт описывает самые общие вещи, независимые от платформ. На этом уровне можно обсуждать что угодно, вплоть до компиляции С++ программы в программу на Лиспе... А что, запросто.
S>Ссылка на переменную оозначает ссылку на значение, хранящееся в переменной.
Ну а ссылка на выражение что означает? А если результат выражения не временный, а вполне постоянный?
V>>Ну? Точно так же как объявление T * const ptr прямо по стандарту не обязательно приводит к выделению памяти под переменную, если выражение вычислимо в compile-time. Потому что константа. А если не вычислимо в рантайм, то в обоих случаях память под переменную еще как выделяется. Потому что переменная константного типа. Это такой хитрый ньюанс С++, который следовало бы иметь ввиду, из-за которого оч разное поведение у статических констант и экземплярных, например. Я именно это тебе и толкую, что для аналогичных случаев оба варианта ведут себя полностью аналогично. S>А я толкую что мы не определяем будет ли то что написано в исходниках функцией по тому заинлайнит компилятор тело или нет. Так же мы не будем определять что является переменной по результату компиляции.
Не, ты не понял. Разное поведение у статический и экземплярных констант потому, что в первом случае под них выделение памяти на усмотрение компилятора (и здесь применимо всё то, что ты сказал), а во втором случае под константу обязательно выделяется память в теле типа-владельца. Ссылки не исключение. Но это очень узко и ничего не объясняет, на самом деле достаточно отличать compile-time константу и runtime константу, тогда твои предположения сойдутся с реальным положением дел. И не только в плане ссылок, а в плане любых констант.
Здравствуйте, samius, Вы писали:
V>>А указатель размещает? S>Указатель размещает значение, т.к. значением указателя является не то значение, на которое он ссылается, а именно адрес того значения.
И как мне получить этот адрес в дотнете из ссылочной переменной? (ты же предположил, что они к указателям ближе)
S>>>ссылочный тип в дотнете семантически ближе к указателю C++, чем к ссылке.
V>>Смотря какой ссылочный. Если тот, который ref в аргументах, то это точная аналогия ссылки С++. S>Ссылочный тип в дотнете ровно один — тот, чьи экземпляры размещаются в управляемой куче. ref-же является чисто модификатором способа передачи аргумента и не образует нового типа в терминах системы типов дотнета.
Гхы.........
class Program {
public void Test(ref int arg) {}
static void Main(string[] args) {
Console.WriteLine(typeof(Program).GetMethod("Test").GetParameters()[0].ParameterType.Name);
}
}
Что выведет?
И кстати, уже можно создавать переменные этого типа в 4-м дотнете, хоть в шарпе пока не поддержали.
V>>В любом случае, для ссылочного типа главное, что он хранит не значение, а его адрес. Даже если это адрес времени компиляции, т.е. константа. S>В общем, ссылочный тип в C++ был бы тождественнен ref-параметрам дотнета, если бы ECMA не позволяла использовать copy-in/copy-out механизм для ref/out параметров
Ну, для случая out-параметров по другому и никак, я же говорил про ref. Допускаю что такое легко обеспечить, коль в дотнете отсутствуют кастомные конструкторы копирования для типов которые могут идти как ref/out, поэтому любая копия гарантированно идентична побитово оригиналу.
S>В этом контексте Вась (immutable) как минимум двое. Один — значение 123, второй — переменная.
123-это литерал, а какое он примет значение, зависит от инициализируемого литералом типа. Не представляю, как литерал может быть не-immutable, в исходниках разве что... ведь он живет только в момент компиляции.
DG>>ты же отвечаешь про stack, как про конкретную штуку из реализации конкретных ЯП, которые в данном случае вообще никакого отношения к дискуссии не имеют.
V>Сказать честно, я и тут не вижу разницы.
я о том, что структура данных stack не обязана один в один реализовываться в виде массива растущего с одной стороны (как это реализовано во многих языках), возможны и другие реализации.
например, stack можно реализовать поверх ассоциативной памяти(ассоциативного массива) — при этом туда-сюда будет меняться имя текущей записи.
при этом это все равно будет stack, как структура данных, но это уже не будет тем самым stack-ом, которые используется в яп.
Здравствуйте, Lloyd, Вы писали:
V>>Если бы способы адресации были не важны, их бы не проходили на первых курсах профильной специальности. Надо понимать что и как работает, чтобы адекватно использовать любую технологию, не делая заведомо неверных допущений (суть проявляя безалаберность и безответственность). Таки запас по эффективности и ресурсам пока еще не тысячекратный, чтобы позволить себе это.
L>Это-то тут причем?
Дык, не представляя способа адресации в каждом конкретном случае трудно получить представление об эффективности в этом месте. Да, обсуждаемые здесь языки таки поддерживают всевозможные способы адресации.
Здравствуйте, DarkGray, Вы писали:
DG>когда vdimas говорит про stack — он имеет ввиду, что при описании семантики локальных переменных (в том числе, когда есть рекурсия) необходимо в любом случае вводить структуру данных LIFO (которая и есть stack-структура данных).
В том-то и дело, что сначала он говорит про стек, как конкретную штуку из конкретной архитектуры конкретного процессора, и конкретный способ реализации высокоуровневых концепций конкретного языка программирования. Который никакого отношения к дискуссии не имеет.
А когда его начинают спрашивать про смысл выражений типа "смещение" и "фрейм" в абстрактной модели, то внезапно оказывается, что речь шла о самой общей концепции LIFO структуры данных, а под "смещением" имелась ввиду вообще любая относительная адресация, в том числе и в DNS.
Это называется "передёргивание".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>при этом, например, перевод из C++ в asm с сохранением вычислительной мощности — является P-задачей, а из asm в C++ — уже NP-задачей. соответственно, C++ получается мощнее чем asm с точки зрения выразительности.
1. Можно как-то обосновать NP-полноту декомпиляции C++?
2. Как связана NP-полнота с мощностью выразительности? Что, если у нас будет два языка, и перевод программы из каждого в другой будет NP-задачей, то оба будут мощнее с точки зрения выразительности?
DG>например, проверка корректности работы с памятью для C#-а является чуть ли не линейной задачей, а проверка C++-программы будет экспонециальной от размера программы (а значит опять же практически не разрешимой). DG>тоже самое и с разными моделями ООП: алгоритмически они эквиваленты, но обладают разной выразительной мощностью
Совершенно верно. И чем больше неопределённости мы вносим в язык программирования, тем сложнее становятся задачи проверки корректности программы.
DG>если что-то непонятно, то лучше спроси. это все-таки формум, а не диссертация по математике, и тут общаются на ЕЯ со всеми его плюсами и недостатками, а не на математической нотации которую ты больше любишь.
Если вы берётесь лезть в теоретическое программирование (а это совершенно необязательно), то придётся научиться пользоваться терминами по назначению, а не как придётся.
DG>ты хороший образец оппонента, который руководствует логикой: если не получается ничего сказать по существу — придеритель к выбранным терминам, если не получилось придраться к терминам придеритель к грамотности.
Отсутствие последовательности в применении терминологии является признаком отсутствия понимания. Зачем вы употребляете выражение "непрерывность времени", если не знаете, что оно означает? Если вам хочется ввести какое-то своё определение, отличное от общепринятого, то либо сначала объясните его, либо готовьтесь быть непонятым.
Объясняю букварь: непрерывность времени — это такое его свойство, что между любыми двумя моментами t1 < t2 есть момент времени t3, такой, что t1 < t3 < t2.
У машины Тьюринга и всех восходящих к ней императивных моделей, включая ООП, время — дискретно. Оно сразу же не удовлетворяет определению непрерывности. Потому что между двумя последовательными "тактами" невозможно вставить третий.
Надо полагать, вы под понятием "непрерывность времени" подразумеваете что-то другое, не то же, что все остальные. Но что именно — для меня загадка.
DG>любое утверждение необходимо обосновывать, а не просто ссылаться на авторитеты. если человек часто выдает какие-то утверждения без обоснований — это показывает, что он не понимает то, о чем он говорит.
Именно это я в ваших постах и наблюдаю. Вы продолжаете делать заведомо неверные утверждения, и не трудитесь их обосновывать.
>> то нужно привыкнуть к тому, что в модели главное — непротиворечивость. DG>а обосновать это можешь? как ты любишь — формально в математической нотации?
Обосновать что? Что противоречивая модель считается неверной? Простите, но это аксиома.
DG>вон диалектика, вообще, утверждает — что нет противоречий -> нет движения(развития), а значит нет и жизни. DG>а ты предлагаешь при моделирование отсутствие противоречий объявить самым главным критерием.
Совершенно верно. Те противоречия, о которых говорит диалектика, не имеют никакого отношения к противоречиям в математических моделях. Я же говорю: нельзя пользоваться словами, не понимая, что они означают. Тем более, что в каждой области значения у терминов свои. Это гуманитарии любят играть словами, путая смежные значения терминов. В инженерных дисциплинах такой подход противопоказан.
S>>Конечно же может. А в чём там проблема? DG>и как задается функция идентичности с точки зрения распределенной системы для объектов которые сейчас спят?
Так же, как и для тех, которые не спят Вся прелесть идентичности в ООП — в том, что она обязана быть независимой от состояния и поведения. В частности, от того, спит сейчас объект или нет.
DG>если лента тьюринга не пространство (как и любая память в других машинах), то что это?
О, я вижу проблески понимания. Да, лента тьюринга — пространство. Но в ООП никакой ленты нет.
DG>неправда. для гарантированности доставки (тем более за разумное время) пространство должно обладать определенными свойствами.
И опять вы термины "пространство" и "время" используете не по назначению. Если бы мы говорили о сообщениях, доставляемых на бумажках в реальном мире, то мы могли бы говорить о "расстояниях" и "времени доставки".
В базовой модели ООП нет никаких расстояний — все объекты равноудалены друг от друга. А понятие "время" ограничивается только категориями "раньше"/"позже", поэтому нельзя судить о том, за разумное ли время доставлено сообщение. Всё, что мы знаем — что сообщение не может быть доставлено раньше, чем отправлено.
DG>есть две модели — в одной все сообщения гарантированно доставляются, в другой — есть несколько различных классов доставки: гарантированная, негарантированная и т.д. DG>первая модель является частью второй, а значит всё смоделированное в первой модели в 1-1 переносится во вторую модель. DG>а обратное как раз неверно. для корректного же описания алгоритма описанного в терминах второй модели при описании в первой модели может уже потребоваться экспонециальный рост сложности (что на практике непременимо).
Простите, но вы продолжаете нести чушь. Я показал вам, как именно в рамках модели с гарантированной доставкой эмулируется негарантированность. Что вас не устраивает?
Очевидно, что любой алгоритм, корректный в вашей модели, будет автоматически корректен и в моей. Обратное, вообще говоря, неверно. Но я вообще затрудняюсь себе представить формальное доказательство корректности алгоритма, описанного для модели с негарантированной доставкой. Вы не могли бы это продемонстрировать, скажем, на примере алгоритма поиска наибольшего общего делителя?
DG>где обоснование?
Обоснование чего? Того, что ООП плохо описывает аналоговый компьютер? Ну так вы сами же начали задавать неразрешимые вопросы в этой области.
S>>Арифметика строится на теории множеств, а не наоборот! Арифметика сложнее теории множеств! DG>что значит сложнее? формализуй.
Значит в ней содержится больше утверждений. В теории множеств вводятся только несколько понятий — дизьюнкция, коньюнкция множеств, мощность множества.
В арифметике на основе теории множеств вводится множество натуральных чисел и операции с ним.
DG>ок. DG>возьмем "отправить Пинг" и исходную программу. DG>в какой точке программы Client может считать, что "отправить Пинг" с точки зрения гарантированности доставки выполнено?
В следующей за вызовом Ping.
DG>асинхронная пара Ping/Pong с последующей синхронной парой Pong/Pong.return
То есть Pong является ответом Ping?
А pong.return является ответом на Pong?
Хорошо — а где тогда ответ на Pong в вашем примере?
И почему вы называете Ping/Pong асинхронной парой?
И что такое r?
DG>тоже самое: асинхронная пара Ping/Pong и синхронная пара Pong/Pong.return DG>изменилась лишь структура связей (в первом случае, сервер был независим от client-а, сейчас он стал зависимым.
О, прекрасно. А если у нас будет менее тривиальный граф объектов, и в ответ на Ping() от этого графа нам внезапно придёт с десяток вызовов от разных участников этого графа — то кто из них будет ответом на Ping?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Так это не не адрес переменной, который фрейм+смещение, а адрес некоторого объекта, который очевидно есть, так как объект размещен в памяти. При этом ссылка != указатель.
V>Во-первых, посмотри внимательно код. Речь шла об адресах переменных на стеке, поэтому код показывает взятие адреса именно стековой переменной. В этом случае адрес не может "просто быть", если сделать указанную ф-ию рекурсивной и каждый раз брать адрес локальной переменной, разве будет этот адрес одним и тем же? Или таки разным в каждом фрейме? Чувствуешь подвох, не? Код один и тот же, но для каждого фрейма будет свой адрес экземпляра одной и той же переменной. Я товарищу Sinclair предлагал чуть порассуждать, чтобы организовать работу такой машины без стека, или без явной его эмуляции (если в железке стека нет). Не выйдет.
А ты вообще про какой стек говоришь? Тот который push\pop или про абстрактную структуру с вложенностью фреймов? Последняя кстати в Lisp не на базе push\pop сделана.
G>>Не понял фразы. Байт-машины нету вообще, есть абстракция, эта абстракция описывается ecma-335, в нем есть GC и верификация. Для указателей есть определенные правила, позволяющие им работать к таком окружении коректно.
V>Пока что мы работаем с двумя наличествующими в природе независимыми реализациями, где "абстракция" описывает как раз конкретную байт-машину, с точностью до расположения бит в инструкциях.
Она же описывает наличие GC и верификатора.
G>>И вообще, указатель это адрес, но нельзя взять любой адрес и превратить его в указатель. Поэтому и адресной арифметики как таковой нету.
V>Во-первых можно взять любой адрес и превратить его таки в указатель.
Не любой, читай Ecma-335
V>Во-вторых, ты случайно не забыл еще, что есть адресная арифметика? Нельзя сравнивать или вычитать адреса из разных областей и разных типов. Например, если у нас есть некий массив элементов по значению, то адреса его элементов сравнивать и вычитать можно, т.к. эти адреса принадлежат одной области памяти и одному типу. Но, обрати внимание, разница указателей — это не кол-во байт м/у этими элементами, а кол-во элементов м/у указываемыми адресами на эти элементы. Вспомнил? Аналогично этому моменту я не понимаю, какие проблемы преобразования индекса в конкретный адрес, если есть информация о типах?
Это ты про C++ говоришь, а не про .NET
V>>>ldloca.s index
V>>>Загружает в стек вычислений адрес локальной переменной с индексом index (короткая форма).
V>>>Определение семантики этой операции байт машины оперирует понятием "локальная переменная", считая его известным читателю, и оперирует термином "адрес", так же считая сей термин общеизвестным. G>>Последнее неверно, оно просто не соотвествует тому что в Ecma написано.
V>Т.е. документация MSDN неверна?
Неточна
адрес, хранящийся в локальной переменной с указанным индексом, помещается в стек.
G>>Во время работы программы все это есть, но этим не надо и вообще говоря нельзя оперировать в терминах .NET. Ты не можешь получить фрейм стека и вычислить адрес переменной. Стековые переменные "адресуются" по индексу и все.
V>Ошибаешься. Я тебе пример привел, в чем проблема? Или сложности с прочтением?
Ты не привел пример получения адреса переменной.
V>Не важно с т.з. стандарта, важно другое, что ldloc означает загрузку локальной переменной, причем, эта операция должна работать непротиворечиво при произвольных вызовах метода, даже рекурсивных. А это не будет работать без формулы: V>el = F(frame, index) V>которая есть суть относительной адресации (или базовой)
А ты какой стек имеешь ввиду?
Здравствуйте, vdimas, Вы писали:
L>>Это-то тут причем?
V>Дык, не представляя способа адресации в каждом конкретном случае трудно получить представление об эффективности в этом месте. Да, обсуждаемые здесь языки таки поддерживают всевозможные способы адресации.
Здравствуйте, Lloyd, Вы писали:
L>>>Это-то тут причем? V>>Дык, не представляя способа адресации в каждом конкретном случае трудно получить представление об эффективности в этом месте. Да, обсуждаемые здесь языки таки поддерживают всевозможные способы адресации. L>А эффективность тут причем?
Здравствуйте, gandjustas, Вы писали:
G>>>Так это не не адрес переменной, который фрейм+смещение, а адрес некоторого объекта, который очевидно есть, так как объект размещен в памяти. При этом ссылка != указатель.
V>>Во-первых, посмотри внимательно код. Речь шла об адресах переменных на стеке, поэтому код показывает взятие адреса именно стековой переменной. В этом случае адрес не может "просто быть", если сделать указанную ф-ию рекурсивной и каждый раз брать адрес локальной переменной, разве будет этот адрес одним и тем же? Или таки разным в каждом фрейме? Чувствуешь подвох, не? Код один и тот же, но для каждого фрейма будет свой адрес экземпляра одной и той же переменной. Я товарищу Sinclair предлагал чуть порассуждать, чтобы организовать работу такой машины без стека, или без явной его эмуляции (если в железке стека нет). Не выйдет.
G>А ты вообще про какой стек говоришь? Тот который push\pop или про абстрактную структуру с вложенностью фреймов?
Ну коль везде говорю про фреймы локальных переменных, то про стек, образованный этими фреймами. Думал и так понятно. Тебе же не приходится каждый раз уточнять про стек в x86 что ты не имел ввиду стек вычислений плавающих регистров x86? Хоть там именно что еще один стек.
G>Последняя кстати в Lisp не на базе push\pop сделана.
Ну и? На базе Cons там классическое дерево т.н. контекста, которое в каждой конкретной ветке (т.н. "версии" для каждого конкретного замыкания) представляет из себя опять же классический стек, ибо видится не графом, но цепочкой от последнего символа к началу. Т.е. обойти эту цепочку можно только по LIFO, что и задекларировано в принципах работы контекста Лиспа и Схемы.
G>>>Не понял фразы. Байт-машины нету вообще, есть абстракция, эта абстракция описывается ecma-335, в нем есть GC и верификация. Для указателей есть определенные правила, позволяющие им работать к таком окружении коректно.
V>>Пока что мы работаем с двумя наличествующими в природе независимыми реализациями, где "абстракция" описывает как раз конкретную байт-машину, с точностью до расположения бит в инструкциях.
G>Она же описывает наличие GC и верификатора.
Ну так есть байт машина с системой команд, к описанию которой я апеллировал, или таки нет?
V>>Т.е. документация MSDN неверна?
G>Неточна
G>
G>адрес, хранящийся в локальной переменной с указанным индексом, помещается в стек.
Вот это номер... Одно из двух, либо невнимательно прочёл приведенный сэмпл, либо вовсе не понимаешь принципов работы value-types в дотнете. В MSDN написано правильно, а ты в 3-х соснах заблудился. причем, в MSDN написано правильно даже для случая ссылочных типов. Надо просто понимать, адрес чего именно загружается на вершину стека вычислений. И таки можно загрузить адрес любой локальной переменной, и потом прочитать в числовом виде значение по этому адресу. Просто у тебя неверное представление, похоже, о происходящем при этом.
G>>>Во время работы программы все это есть, но этим не надо и вообще говоря нельзя оперировать в терминах .NET. Ты не можешь получить фрейм стека и вычислить адрес переменной. Стековые переменные "адресуются" по индексу и все.
V>>Ошибаешься. Я тебе пример привел, в чем проблема? Или сложности с прочтением? G>Ты не привел пример получения адреса переменной.
Таки привел...
Как раз тот самый случай для демонстрации популярного мема: "некоторым программистам понятие указателей не дается".
V>>Не важно с т.з. стандарта, важно другое, что ldloc означает загрузку локальной переменной, причем, эта операция должна работать непротиворечиво при произвольных вызовах метода, даже рекурсивных. А это не будет работать без формулы: V>>el = F(frame, index) V>>которая есть суть относительной адресации (или базовой) G>А ты какой стек имеешь ввиду?
Очевидно из этого:
el = F(frame, index)
имею ввиду тот, в котором живут фреймы (или который ими образован).
Здравствуйте, Sinclair, Вы писали:
DG>>когда vdimas говорит про stack — он имеет ввиду, что при описании семантики локальных переменных (в том числе, когда есть рекурсия) необходимо в любом случае вводить структуру данных LIFO (которая и есть stack-структура данных). S>В том-то и дело, что сначала он говорит про стек, как конкретную штуку из конкретной архитектуры конкретного процессора, и конкретный способ реализации высокоуровневых концепций конкретного языка программирования. Который никакого отношения к дискуссии не имеет.
Разве? А покажи мне способ доступа к "конкретной штуке из конкретной архитектуры конкретного процессора" на примере того же Паскаля, к который я брал для сравнения. Сможешь объяснить, чем фреймы локальных переменных для программ на Паскале отличаются от фреймов локальных переменных дотнета? Т.е. чем одна абстракция, которая только и доступна из ЯП, отличается от другой.
S>и конкретный способ реализации высокоуровневых концепций конкретного языка
Насколько конкретный-то? Сразу и было сказано, что как-ни крути, нужен стек, либо имеющийся, либо его придется эмулировать. А уж эмулировать можно столькими способами, сколько фантазии хватит. Я догадываюсь, что ты имеешь ввиду, наверно свое представление о стеке, как о непрерывной области байт, растущей в обратном направлении? Но ты этого не найдешь у меня, это додумка за оппонента. Тем более, что оппонент работал и со стеками растущими в прямом направлении, и со стеками, составленными из фрагментов. Разные реализации, подумаешь, которые абсолютно до фени, т.к. в любом высокоуровневом ЯП тебе уже дается готовый локальный фрейм... а уж как он сформирован, тебе всё-равно недоступно, что из С++/Паскаля, что из дотнета. В общем, это не важно, не на том ты пытаешься сосредоточиться.
S>А когда его начинают спрашивать про смысл выражений типа "смещение" и "фрейм" в абстрактной модели, то внезапно оказывается, что речь шла о самой общей концепции LIFO структуры данных, а под "смещением" имелась ввиду вообще любая относительная адресация, в том числе и в DNS.
Э нет, смещение в рамках конкретного фрейма — это фундаменально. Независимо от того, речь об абстрактной структуре данных LIFO, либо о конкретной ее реализации. Так что, никаких "внезапно", я на этом именно настаиваю с самого начала.
S>Это называется "передёргивание".
Ну ты же полез в дебри ассоциативной адресации, пришлось показывать тебе аналогичные приемы в ней... Меня она интересует постольку-поскольку, на самом деле, тем более, что примерный способ перевода абстракций MSIL в конкретные числа показал здесь: http://www.rsdn.ru/forum/philosophy/4508569.1.aspx
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>>>Так это не не адрес переменной, который фрейм+смещение, а адрес некоторого объекта, который очевидно есть, так как объект размещен в памяти. При этом ссылка != указатель.
V>>>Во-первых, посмотри внимательно код. Речь шла об адресах переменных на стеке, поэтому код показывает взятие адреса именно стековой переменной. В этом случае адрес не может "просто быть", если сделать указанную ф-ию рекурсивной и каждый раз брать адрес локальной переменной, разве будет этот адрес одним и тем же? Или таки разным в каждом фрейме? Чувствуешь подвох, не? Код один и тот же, но для каждого фрейма будет свой адрес экземпляра одной и той же переменной. Я товарищу Sinclair предлагал чуть порассуждать, чтобы организовать работу такой машины без стека, или без явной его эмуляции (если в железке стека нет). Не выйдет.
G>>А ты вообще про какой стек говоришь? Тот который push\pop или про абстрактную структуру с вложенностью фреймов?
V>Ну коль везде говорю про фреймы локальных переменных, то про стек, образованный этими фреймами. Думал и так понятно. Тебе же не приходится каждый раз уточнять про стек в x86 что ты не имел ввиду стек вычислений плавающих регистров x86? Хоть там именно что еще один стек.
Непонятно потому что терминологию низкого уровня ты применяешь для высокоуровневых вещей.
G>>>>Не понял фразы. Байт-машины нету вообще, есть абстракция, эта абстракция описывается ecma-335, в нем есть GC и верификация. Для указателей есть определенные правила, позволяющие им работать к таком окружении коректно.
V>>>Пока что мы работаем с двумя наличествующими в природе независимыми реализациями, где "абстракция" описывает как раз конкретную байт-машину, с точностью до расположения бит в инструкциях.
G>>Она же описывает наличие GC и верификатора.
V>Ну так есть байт машина с системой команд, к описанию которой я апеллировал, или таки нет?
Да, это все входит в описание CLR. Это ecma-335 + описание IL.
V>>>Т.е. документация MSDN неверна?
G>>Неточна
G>>
G>>адрес, хранящийся в локальной переменной с указанным индексом, помещается в стек.
V>Вот это номер... Одно из двух, либо невнимательно прочёл приведенный сэмпл, либо вовсе не понимаешь принципов работы value-types в дотнете. В MSDN написано правильно, а ты в 3-х соснах заблудился. причем, в MSDN написано правильно даже для случая ссылочных типов. Надо просто понимать, адрес чего именно загружается на вершину стека вычислений. И таки можно загрузить адрес любой локальной переменной, и потом прочитать в числовом виде значение по этому адресу. Просто у тебя неверное представление, похоже, о происходящем при этом.
Ты опять провалился на тот уровень, который не описывается ecma-335. Ты оперируешь сведениями, доставшимися тебе от C++. Кстати выше ты писал про абстрактный стек, а тут о чем ты пишешь — непонятно.
G>>>>Во время работы программы все это есть, но этим не надо и вообще говоря нельзя оперировать в терминах .NET. Ты не можешь получить фрейм стека и вычислить адрес переменной. Стековые переменные "адресуются" по индексу и все.
V>>>Ошибаешься. Я тебе пример привел, в чем проблема? Или сложности с прочтением? G>>Ты не привел пример получения адреса переменной.
V>Таки привел... V>Как раз тот самый случай для демонстрации популярного мема: "некоторым программистам понятие указателей не дается".
IL работает в терминах абстрактного стека, где "переменная" != адрес и у самих переменных адреса нету. Так что ты опять промахнулся.
V>>>Не важно с т.з. стандарта, важно другое, что ldloc означает загрузку локальной переменной, причем, эта операция должна работать непротиворечиво при произвольных вызовах метода, даже рекурсивных. А это не будет работать без формулы: V>>>el = F(frame, index) V>>>которая есть суть относительной адресации (или базовой) G>>А ты какой стек имеешь ввиду?
V>Очевидно из этого: V>el = F(frame, index) V>имею ввиду тот, в котором живут фреймы (или который ими образован).
Такие "адреса" не предполагают арифметику, так как index вообще говоря не обязан быть числовым.
DG>>при этом, например, перевод из C++ в asm с сохранением вычислительной мощности — является P-задачей, а из asm в C++ — уже NP-задачей. соответственно, C++ получается мощнее чем asm с точки зрения выразительности. S>1. Можно как-то обосновать NP-полноту декомпиляции C++?
такое сильное утверждение доказать не готов.
но утверждаю, что как минимум на текущий момент: задача перевода из asm-а в C++ требует существенно большей вычислительной сложности, чем из C++ в asm
S>2. Как связана NP-полнота с мощностью выразительности? Что, если у нас будет два языка, и перевод программы из каждого в другой будет NP-задачей, то оба будут мощнее с точки зрения выразительности?
нет, конечно.
язык X выразительнее языка Y: если перевод программы (с сохранением вычислительной сложности) из языка X в язык Y требует существенно меньшей вычислительной сложности, чем из языка Y в X
также еще требуется, чтобы на обоих языках можно было решать одни и те же задачи (все или в какой-то области)
DG>>например, проверка корректности работы с памятью для C#-а является чуть ли не линейной задачей, а проверка C++-программы будет экспонециальной от размера программы (а значит опять же практически не разрешимой). DG>>тоже самое и с разными моделями ООП: алгоритмически они эквиваленты, но обладают разной выразительной мощностью S>Совершенно верно. И чем больше неопределённости мы вносим в язык программирования, тем сложнее становятся задачи проверки корректности программы.
во-первых, неопределенность бывает важной и неважной.
например, в C-и есть неопределенность как именно будут размещены локальные переменные: в регистрах процессора или на стеке, но это слабо мешает проверке корректности
во-вторых, увеличение неопределенности может компенсироваться существенным снижением объема программы, что важно, т.к. многие алгоритмы по работе с кодом программы имеют сложность O(n^2) и выше
DG>>если что-то непонятно, то лучше спроси. это все-таки формум, а не диссертация по математике, и тут общаются на ЕЯ со всеми его плюсами и недостатками, а не на математической нотации которую ты больше любишь. S>Если вы берётесь лезть в теоретическое программирование (а это совершенно необязательно), то придётся научиться пользоваться терминами по назначению, а не как придётся.
я их и использую назначению. если же хочется полной формализации, то это нереально в рамках форума: это сразу раздувает на порядки объем высказываний и требует существенно больше времени.
DG>>ты хороший образец оппонента, который руководствует логикой: если не получается ничего сказать по существу — придеритель к выбранным терминам, если не получилось придраться к терминам придеритель к грамотности. S>Отсутствие последовательности в применении терминологии является признаком отсутствия понимания. Зачем вы употребляете выражение "непрерывность времени", если не знаете, что оно означает? Если вам хочется ввести какое-то своё определение, отличное от общепринятого, то либо сначала объясните его, либо готовьтесь быть непонятым.
еще раз повторяю, что непрерывностей много, и если ты знаешь тольку одну (непрерывность вещественного пространства) — это не значит, что только оно одно и есть.
S>Объясняю букварь: непрерывность времени — это такое его свойство, что между любыми двумя моментами t1 < t2 есть момент времени t3, такой, что t1 < t3 < t2.
во-первых: это — не есть определение непрерывности. То, что ты написал — это лишь следствие для вещественного пространства.
точное определение непрерывности:
Непреры́вное отображе́ние или непрерывная функция — это такое отображение, у которого малые изменения аргумента приводят к малым изменениям значения отображения.
и это определение инвариантно относительно пространства: вещественного или дискретного.
во-вторых, прочти что-нибудь еще кроме букваря, например, дискретную математику
вот тебе определение непрерывности из дискретной математики
Дискретная математика Непрерывные отображения
Пусть Е и F – топологические пространства, и пусть f – отображение пространства Е в F.
f: E ® F.
Непрерывность отображения состоит в том, что точки, близкие друг к другу в множестве Е, отодражаются в точки, близкие друг к другу в множестве F.
Определение. Отображение f: E ® F называется непрерывным в точке р, если для любой окрестности V точки f(p) в множестве F существует такая окрестность U точки в множестве Е, что f(U) Ì V. Отображение f называется непрерывным, если оно непрерывно в каждой точке пространства Е.
Особое значение имеют те непрерывности отображения, для которых существует непрерывное обратное отображение
S>У машины Тьюринга и всех восходящих к ней императивных моделей, включая ООП, время — дискретно. Оно сразу же не удовлетворяет определению непрерывности. Потому что между двумя последовательными "тактами" невозможно вставить третий. S>Надо полагать, вы под понятием "непрерывность времени" подразумеваете что-то другое, не то же, что все остальные. Но что именно — для меня загадка.
я понимаю то, что и все. непрерывность дискретного пространства, если можно выделить отдельные кванты времени; и непрерывность вещественного пространства — если таких квантов нет.
DG>>любое утверждение необходимо обосновывать, а не просто ссылаться на авторитеты. если человек часто выдает какие-то утверждения без обоснований — это показывает, что он не понимает то, о чем он говорит. S>Именно это я в ваших постах и наблюдаю. Вы продолжаете делать заведомо неверные утверждения, и не трудитесь их обосновывать.
какие например?
все претензии до этого были к терминам, а не к обоснованиям утверждений.
>>> то нужно привыкнуть к тому, что в модели главное — непротиворечивость. DG>>а обосновать это можешь? как ты любишь — формально в математической нотации? S>Обосновать что? Что противоречивая модель считается неверной? Простите, но это аксиома.
аксиома — в какой аксиоматике?
из противоречия следует неверность только в булевой логике, но кроме булевой логики есть много чего еще (прочитай все-таки хоть что-нибудь кроме букварей)
но в булевой логике невозможно удобно (начинает экспонециально расти кол-во термов) записать даже следующую ситуацию:
автомобиль не умеет плавать
автомобиль-амфибия является автомобилем
автомобиль-амфибия умеет плавать
DG>>вон диалектика, вообще, утверждает — что нет противоречий -> нет движения(развития), а значит нет и жизни. DG>>а ты предлагаешь при моделирование отсутствие противоречий объявить самым главным критерием. S>Совершенно верно. Те противоречия, о которых говорит диалектика, не имеют никакого отношения к противоречиям в математических моделях. Я же говорю: нельзя пользоваться словами, не понимая, что они означают. Тем более, что в каждой области значения у терминов свои. Это гуманитарии любят играть словами, путая смежные значения терминов. В инженерных дисциплинах такой подход противопоказан.
такте действительное есть в инженерных дисциплинах на уровне букваря.
S>>>Конечно же может. А в чём там проблема? DG>>и как задается функция идентичности с точки зрения распределенной системы для объектов которые сейчас спят? S>Так же, как и для тех, которые не спят Вся прелесть идентичности в ООП — в том, что она обязана быть независимой от состояния и поведения. В частности, от того, спит сейчас объект или нет.
ты функцию приведи. и заодно объясни, как ей можно воспользоваться для тех объектов, которые спят.
DG>>если лента тьюринга не пространство (как и любая память в других машинах), то что это? S>О, я вижу проблески понимания. Да, лента тьюринга — пространство. Но в ООП никакой ленты нет.
нет, но есть пространство.
на всяком случае уточню, что пространство в математическом понимании. а то сейчас выяснится, что ты под пространством понимаешь лишь материальное пространство.
DG>>неправда. для гарантированности доставки (тем более за разумное время) пространство должно обладать определенными свойствами. S>И опять вы термины "пространство" и "время" используете не по назначению. Если бы мы говорили о сообщениях, доставляемых на бумажках в реальном мире, то мы могли бы говорить о "расстояниях" и "времени доставки".
действительно выяснилось, что ты не знаешь что пространство бывает и не материальным.
S>В базовой модели ООП нет никаких расстояний — все объекты равноудалены друг от друга. А понятие "время" ограничивается только категориями "раньше"/"позже", поэтому нельзя судить о том, за разумное ли время доставлено сообщение. Всё, что мы знаем — что
сообщение не может быть доставлено раньше, чем отправлено.
такого сильного утверждения в ООП нет.
есть другое утверждение: сообщение не может быть доставлено раньше, чем начато отправление сообщения.
и так же надо добавить еще кучу допущений: что это верно лишь в системе времени отправителя и т.д.
DG>>есть две модели — в одной все сообщения гарантированно доставляются, в другой — есть несколько различных классов доставки: гарантированная, негарантированная и т.д. DG>>первая модель является частью второй, а значит всё смоделированное в первой модели в 1-1 переносится во вторую модель. DG>>а обратное как раз неверно. для корректного же описания алгоритма описанного в терминах второй модели при описании в первой модели может уже потребоваться экспонециальный рост сложности (что на практике непременимо). S>Простите, но вы продолжаете нести чушь. Я показал вам, как именно в рамках модели с гарантированной доставкой эмулируется негарантированность. Что вас не устраивает?
экспонециальный рост утверждений и термов по сравнению с нечеткими моделям для описывания одних и тех же ситуаций.
S>Очевидно, что любой алгоритм, корректный в вашей модели, будет автоматически корректен и в моей. Обратное, вообще говоря, неверно. Но я вообще затрудняюсь себе представить формальное доказательство корректности алгоритма, описанного для модели с негарантированной доставкой. Вы не могли бы это продемонстрировать, скажем, на примере алгоритма поиска наибольшего общего делителя?
в данной задаче отличия и не будет, потому что я уже говорил, что нечеткая логика включает в себя четкую (также как вещественные числа включают в себя целые)
но вот отличие появится если необходимо записать параллельный алгоритм поиска общего делителя для набора исполнителей-делителей с которыми нет гарантированной связи.
DG>>где обоснование? S>Обоснование чего? Того, что ООП плохо описывает аналоговый компьютер? Ну так вы сами же начали задавать неразрешимые вопросы в этой области.
ты уже начинаешь думать. это хорошо. наука как раз и начинается с попыток ответа на вопросы, которые кажутся неразрешимыми.
Здравствуйте, DarkGray, Вы писали:
DG>такое сильное утверждение доказать не готов.
Тогда не стоит его делать.
DG>нет, конечно. DG>язык X выразительнее языка Y: если перевод программы (с сохранением вычислительной сложности) из языка X в язык Y требует существенно меньшей вычислительной сложности, чем из языка Y в X
Интересная гипотеза. И мы ей непременно займёмся, но в другой раз. Пока же достаточно будет намекнуть про то, что некоторые алгоритмы вывода типов в ЯП высокого уровня требуют чудовищной вычислительной сложности при переводе, скажем, в MSIL. При этом преобразование в обратную сторону относительно тривиально.
DG>во-первых, неопределенность бывает важной и неважной. DG>например, в C-и есть неопределенность как именно будут размещены локальные переменные: в регистрах процессора или на стеке, но это слабо мешает проверке корректности
Нет, просто бывают разного рода неопределённости. Неопределённость размещения переменных только помогает, т.к. не даёт программе заложиться на неочевидные побочные эффекты. Неопределённость семантики мешает проверке корректности.
См., например, aliasing problem.
DG>я их и использую назначению. если же хочется полной формализации, то это нереально в рамках форума: это сразу раздувает на порядки объем высказываний и требует существенно больше времени.
Нет, вы не используете их по назначению. Не надо полной формализации — достаточно, чтобы вы использовали термины в общепринятых смыслах.
S>>Объясняю букварь: непрерывность времени — это такое его свойство, что между любыми двумя моментами t1 < t2 есть момент времени t3, такой, что t1 < t3 < t2.
DG>во-первых: это — не есть определение непрерывности. То, что ты написал — это лишь следствие для вещественного пространства.
OMG! Какое ещё "вещественное пространство"? Какое ещё нафиг "следствие"? Я же говорю — не надо употреблять термины, значение которых непонятно! Я привёл вам определение термина "непрерывность времени".
DG> точное определение непрерывности: DG>
DG>Непреры́вное отображе́ние или непрерывная функция — это такое отображение, у которого малые изменения аргумента приводят к малым изменениям значения отображения.
OMFG! Вы понимаете разницу между терминами "непрерывное отображение" и "непрерывность времени"? Вы берёте термин из одной области, пилите пополам и применяете в совершенно другой области! DG>и это определение инвариантно относительно пространства: вещественного или дискретного.
При чём тут пространство опять? Что такое "инвариантно", в вашем понимании? Откуда вообще взялось "отображение"? Отображение чего на что?
DG>вот тебе определение непрерывности из дискретной математики
Это не определение "непрерывности". Нельзя получить определение термина "непрерывнсть", взяв определение термина "непрерывное отображение", и выбросив из термина непонятое слово.
DG>я понимаю то, что и все. непрерывность дискретного пространства, если можно выделить отдельные кванты времени; и непрерывность вещественного пространства — если таких квантов нет.
Вы сначала определитесь, о времени или о пространстве вы говорите.
DG>какие например? DG>все претензии до этого были к терминам, а не к обоснованиям утверждений.
Например, про NP-полноту задачи декомпиляции.
DG>аксиома — в какой аксиоматике?
В математике метаматематик.
DG>ты функцию приведи. и заодно объясни, как ей можно воспользоваться для тех объектов, которые спят.
То есть надо привести конкретную функцию для абстрактной системы?
Как интерееесно! Ну ок, давайте так:
DG>на всяком случае уточню, что пространство в математическом понимании. а то сейчас выяснится, что ты под пространством понимаешь лишь материальное пространство.
Давайте всё же уточним, какое "пространство в математическом понимании" имеется в виду.
Дело в том, что в математике слово «пространство» употребляется в большом наборе сложных терминов. В большинстве случаев оно означает множество, которое обладает некоторыми свойствами. В этом смысле пространство в ООП есть — "пространство объектов". Но оно не является, к примеру, метрическим пространством.
DG>такого сильного утверждения в ООП нет. DG>есть другое утверждение: сообщение не может быть доставлено раньше, чем начато отправление сообщения.
В ООП время дискретно. Так что нет смысла раздельно говорить о начале и окончании отправки сообщения. DG>и так же надо добавить еще кучу допущений: что это верно лишь в системе времени отправителя и т.д.
Доставка сообщения всегда происходит в "системе времени" получателя. А отправление — отправителя.
Если бы у нас не было допущения о том, что доставка происходит не раньше отправления, то мы не могли бы никак синхронизовывать локальные времена разных объектов.
В частности, это бы приводило к парадоксам вроде получения реакции на сообщение раньше отправки самого сообщения.
DG>экспонециальный рост утверждений и термов по сравнению с нечеткими моделям для описывания одних и тех же ситуаций.
Откуда берётся экспоненциальный рост?
DG>но вот отличие появится если необходимо записать параллельный алгоритм поиска общего делителя для набора исполнителей-делителей с которыми нет гарантированной связи.
М-м. Ок, без проблем. Как вы планируете доказывать корректность этого алгоритма?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>нет, конечно. DG>>язык X выразительнее языка Y: если перевод программы (с сохранением вычислительной сложности) из языка X в язык Y требует существенно меньшей вычислительной сложности, чем из языка Y в X S>Интересная гипотеза. И мы ей непременно займёмся, но в другой раз. Пока же достаточно будет намекнуть про то, что некоторые алгоритмы вывода типов в ЯП высокого уровня требуют чудовищной вычислительной сложности при переводе, скажем, в MSIL. При этом преобразование в обратную сторону относительно тривиально.
мне, кажется, ты упускаешь основной момент: обратное преобразование из msil должно не просто обратно преобразовать в C#, оно еще должна корректно востановить, какие явные преобразования типов можно выкинуть, а какие нельзя. и соответственно оно включает в себя задачу: здесь типы вывести можно или нельзя
тот же Reflector кстати с этим периодически ошибается. даже в сложных арифметических выражениях (либо ставит лишние, либо не ставит нужных)
DG>>во-первых, неопределенность бывает важной и неважной. DG>>например, в C-и есть неопределенность как именно будут размещены локальные переменные: в регистрах процессора или на стеке, но это слабо мешает проверке корректности S>Нет, просто бывают разного рода неопределённости. Неопределённость размещения переменных только помогает, т.к. не даёт программе заложиться на неочевидные побочные эффекты. Неопределённость семантики мешает проверке корректности.
т.е. ты сам знаешь, что неопределенность неопределенности рознь, но при этом делаешь сильное заявление, что
И чем больше неопределённости мы вносим в язык программирования, тем сложнее становятся задачи проверки корректности программы.
а сейчас выясняется, что ты на самое деле хотел сделать более слабое заявление
И чем больше неопределённости семантики мы вносим в язык программирования, тем сложнее становятся задачи проверки корректности программы.
на самое деле и это заявление слишком сильное.
важно только то, что влияет на неопределенность существенной часть результата.
например, неопределенность как именно делается округления, или с какой точностью (до 8-го знака или до 20-го) производятся вычисления, идентичны ли два каких-то левых объекта или не идентичны и т.д. — всё это не важно для тех программ для которых это не влияет на существенную часть результата.
зы DG>>такое сильное утверждение доказать не готов. S>Тогда не стоит его делать.
вот-вот другим запрещаем, а сами делаем.
S> Я привёл вам определение термина "непрерывность времени".
из своего головы или откуда? опять из букваря?
на всякий случай намекну, что в текущий момент в физике не доказано, что время в реальном мире не является дискретным.
и что на текущий момент, есть как раз неопределенность — считать реальное время непрерывным или дискретным.
DG>> точное определение непрерывности: DG>>
DG>>Непреры́вное отображе́ние или непрерывная функция — это такое отображение, у которого малые изменения аргумента приводят к малым изменениям значения отображения.
S>OMFG! Вы понимаете разницу между терминами "непрерывное отображение" и "непрерывность времени"? Вы берёте термин из одной области, пилите пополам и применяете в совершенно другой области! DG>>и это определение инвариантно относительно пространства: вещественного или дискретного. S>При чём тут пространство опять? Что такое "инвариантно", в вашем понимании? Откуда вообще взялось "отображение"? Отображение чего на что?
как минимум советую вернуться к исходному моему утверждению, и убедиться что там шла речь про отображение одного времени на другое.
DG>>ты функцию приведи. и заодно объясни, как ей можно воспользоваться для тех объектов, которые спят. S>То есть надо привести конкретную функцию для абстрактной системы? S>Как интерееесно! Ну ок, давайте так: S>
и что надо передать в эту функцию в качестве объекта, если он спит?
DG>>на всяком случае уточню, что пространство в математическом понимании. а то сейчас выяснится, что ты под пространством понимаешь лишь материальное пространство. S>Давайте всё же уточним, какое "пространство в математическом понимании" имеется в виду. S>Дело в том, что в математике слово «пространство» употребляется в большом наборе сложных терминов. В большинстве случаев оно означает множество, которое обладает некоторыми свойствами. В этом смысле пространство в ООП есть — "пространство объектов". Но оно не является, к примеру, метрическим пространством.
т.е. пространство оказывается уже есть. уже хорошо.
может ли это пространство быть несвязанным? и что про это говорит ООП?
может ли оно в разные время быть, то связанным, то не связанным?
DG>>такого сильного утверждения в ООП нет. DG>>есть другое утверждение: сообщение не может быть доставлено раньше, чем начато отправление сообщения. S>В ООП время дискретно. Так что нет смысла раздельно говорить о начале и окончании отправки сообщения.
это ничего не меняет, потому что ООП не говорит, что отправка сообщения должно занимать один квант времени с точки зрения отправителя.
а если отправка сообщения занимает несколько квантов времени, то есть квант начала и квант конца.
еще есть всякие сложности, что в объекте может быть несколько потоков управления, и тогда у каждого свое понятие времени.
и с точки зрения объекта целиком кванты времени могут щелкать следующим образом:
1-ый поток: начало кванта отправки сообщения
2-ой поток: раз квант времени
2-ой поток: второй квант времени
2-ой поток: третий квант времени
1-ый поток: конец кванта отправки сообщения
1-ый поток: следующий квант
соответственно с точки зрения такого объекта есть две ситуации:
1-ый поток: начало кванта отправки сообщения
2-ой поток: раз квант времени
2-ой поток: второй квант времени
2-ой поток: третий квант времени
1-ый поток: конец кванта отправки сообщения
1-ый поток: следующий квант
..
1-ый или 2-ой поток: пришел ответ
и
1-ый поток: начало кванта отправки сообщения
2-ой поток: раз квант времени
2-ой поток: второй квант времени
2-ой поток: пришел ответ на сообщение
2-ой поток: третий квант времени
1-ый поток: конец кванта отправки сообщения
1-ый поток: следующий квант
и во второй ситуации необходимо все-таки разбираться — в какой квант времени считается, что сообщение отправлено
зы
подчеркну, что логический поток управления лишь примерно соответственно thread-у
в примере, который я приводил — там один thread, но два потока управления
DG>>и так же надо добавить еще кучу допущений: что это верно лишь в системе времени отправителя и т.д. S>Доставка сообщения всегда происходит в "системе времени" получателя. А отправление — отправителя. S>Если бы у нас не было допущения о том, что доставка происходит не раньше отправления, то мы не могли бы никак синхронизовывать локальные времена разных объектов.
этого требует ООП?
S>В частности, это бы приводило к парадоксам вроде получения реакции на сообщение раньше отправки самого сообщения.
это тоже требует ООП, чтобы не было таких парадоксов? в каком пункте?
DG>>экспонециальный рост утверждений и термов по сравнению с нечеткими моделям для описывания одних и тех же ситуаций. S>Откуда берётся экспоненциальный рост?
потому что для фиксирования каждой неопределенности необходимо весь мир умножить на два: термы, которые будут соответствовать состоянию неопределенности, когда оно находится в состоянии да, и термы, которые будут соответствовать состоянию неопределенности, когда оно находится в состоянии нет.
и того получается 2^кол-во неопределенностей
DG>>но вот отличие появится если необходимо записать параллельный алгоритм поиска общего делителя для набора исполнителей-делителей с которыми нет гарантированной связи. S>М-м. Ок, без проблем. Как вы планируете доказывать корректность этого алгоритма?
примерно также как доказывается традиционный алгоритм НОД:
для доказательства завершенности: доказывается что каждое следующее состояние не хуже, чем предыдущее, и при этом что рано или поздно для каждого состояние будет переход в более лучшее состояние.
для правильности доказывается, что каждый переход между состояниями был легитимным
Здравствуйте, gandjustas, Вы писали:
G>>>А ты вообще про какой стек говоришь? Тот который push\pop или про абстрактную структуру с вложенностью фреймов?
V>>Ну коль везде говорю про фреймы локальных переменных, то про стек, образованный этими фреймами. Думал и так понятно. Тебе же не приходится каждый раз уточнять про стек в x86 что ты не имел ввиду стек вычислений плавающих регистров x86? Хоть там именно что еще один стек.
G>Непонятно потому что терминологию низкого уровня ты применяешь для высокоуровневых вещей.
Уточни, какой термин тебе показался низкоуровневым?
V>>Ну так есть байт машина с системой команд, к описанию которой я апеллировал, или таки нет? G>Да, это все входит в описание CLR. Это ecma-335 + описание IL.
Наконец-то. Итак, возвращаясь к началу, оперирует таки байт-машина адресами или нет? Чтобы ты не тратил время, скажу что оперирует. Даже имеет команды перевода адреса в ширину слова данных. Наверно это некий "запас" для тех архитектур (напр. гардвардских), где разрядность адреса не равна разрядности данных. Например, в некоторых PIC-контроллерах адреса имеют 7, 11, 12, 13 и т.д. бит в опкодах. А еще где-то адреса описывают не сплошню память, а сегментированную. А еще где-то адрес всегда относительный, и для целей этого преобразования нужно брать значение базы. Понимаешь, к чему я клоню? Что т.н. "абстракция", на которой вы настаиваете, не только не оторвана от реального мира, наоборот, предоставляет ср-ва, для приведения всевозможных схем к модели "плоской" памяти, которой оперирует байт-машина, коль целевой адрес должен быть непротиворечиво приводим в число прямо по стандарту.
Ну и обращение к полям объектов — это же классическая базовая адресация (из документации по ldflda):
The stack transitional behavior, in sequential order, is:
— An object reference (or pointer) is pushed onto the stack.
— The object reference (or pointer) is popped from the stack; the address of the specified field in the object is found.
— The address of the specified field is pushed onto the stack.
V>>Вот это номер... Одно из двух, либо невнимательно прочёл приведенный сэмпл, либо вовсе не понимаешь принципов работы value-types в дотнете. В MSDN написано правильно, а ты в 3-х соснах заблудился. причем, в MSDN написано правильно даже для случая ссылочных типов. Надо просто понимать, адрес чего именно загружается на вершину стека вычислений. И таки можно загрузить адрес любой локальной переменной, и потом прочитать в числовом виде значение по этому адресу. Просто у тебя неверное представление, похоже, о происходящем при этом.
G>Ты опять провалился на тот уровень, который не описывается ecma-335. Ты оперируешь сведениями, доставшимися тебе от C++.
Не юли, не убежишь. Ты считал, что описание в MSDN некорректно, и даже исправил его. Спасибо, теперь хоть понятно, что именно тебе непонятно. Я отсылал тебя к понятию value-type, ты вернулся с тем же представлением... Заметь, речь исключительно о дотнете. Причем тут С++, вообще, если ты показываешь обычное непонимание совсем другого предмета. Ну попроси старших товарищей, которым ты доверяешь, объяснить приведенный мною пример, раз ты не умеешь непредвзято слушать программиста, использующего в числе прочих технологий язык С++.
G>IL работает в терминах абстрактного стека, где "переменная" != адрес и у самих переменных адреса нету. Так что ты опять промахнулся.
Как поймешь написанное, попробуй прочесть опкоды из моего примера еще раз...
G>>>А ты какой стек имеешь ввиду?
V>>Очевидно из этого: V>>el = F(frame, index) V>>имею ввиду тот, в котором живут фреймы (или который ими образован).
G>Такие "адреса" не предполагают арифметику, так как index вообще говоря не обязан быть числовым.
Угу, еще и стандарт был прочитан хотя и многократно, но ни разу полностью.
Partition I: Concepts and Architecture – Describes the overall architecture of the CLI, and provides the normative description of the Common Type System (CTS), the Virtual Execution System (VES), and the Common Language Specification (CLS). It also provides an informative description of the metadata.
Partition II: Metadata Definition and Semantics – Provides the normative description of the metadata: its physical layout (as a file format), its logical contents (as a set of tables and their relationships), and its semantics (as seen from a hypothetical assembler, ilasm).
Partition III: CIL Instruction Set – Describes the Common Intermediate Language (CIL) instruction set.
Partition IV: Profiles and Libraries – Provides an overview of the CLI Libraries, and a specification of their factoring into Profiles and Libraries. A companion file, CLILibrary.xml, considered to be part of this Partition, but distributed in XML format, provides details of each class, value type, and interface in the CLI Libraries.
Partition V: Debug Interchange Format– Describes a standard way to interchange debugging information between CLI producers and consumers.
Partition VI: Annexes – Contains some sample programs written in CIL Assembly Language (ILAsm), information about a particular implementation of an assembler, a machine-readable description of the CIL instruction set which can be used to derive parts of the grammar used by this assembler as well as other tools that manipulate CIL, a set of guidelines used in the design of the libraries of Partition IV, and portability considerations.
Похоже, дальше вводной части стандарта (т.е. раздела I) ты не асилил. Индексы локальных переменных по стандарту — числовые, разрядностью 16 (в короткой форме разрядность 8).
Здравствуйте, Lloyd, Вы писали:
L>>>А эффективность тут причем? V>>Не зависит от способа адресации разве? L>А способ адресации тут причем?
Хм, даже такой толстый намек не помог?
L>Я еще раз повторюсь: вы путаете понятия времени исполнения и понятия языка программирования.
В каком случае я это путаю? Когда пишу программу "в стол" или чтобы она потом таки работала с ненулевой пользой?
Я вижу непонимание способов адресации и разницы м/у ними в плане эффективности. Обсуждать сфероконей можно бесконечно, это очень важное и нужное дело, разумеется... Но, не понимая особенностей способов адресации, нельзя сказать, что понимаешь инструмент, которым пользуешься.
Здравствуйте, vdimas, Вы писали:
V>Я вижу непонимание способов адресации и разницы м/у ними в плане эффективности. Обсуждать сфероконей можно бесконечно, это очень важное и нужное дело, разумеется... Но, не понимая особенностей способов адресации, нельзя сказать, что понимаешь инструмент, которым пользуешься.
Вы говорите хорошие и правильные слова, которые вряд ли кто возьмется оспаривать.
Но они не имеют никакого отношения к моей реплике, на которую вы взялись отвечать. Совсем никакого.
Здравствуйте, DarkGray, Вы писали:
DG>я о том, что структура данных stack не обязана один в один реализовываться в виде массива растущего с одной стороны (как это реализовано во многих языках), возможны и другие реализации.
Дык, языки этого не требуют и нигде явно не было этого сказано. Ну да, конкретные реализации компиляторов для конкретных платформ могут использовать сплошные (довольно большие) области памяти под стек, при чем тут? Мы эти моменты даже не обсуждали, это было приписано мне, и то, далеко не сразу. Несмотря на предварительное упоминание мною архитектур, на которых стек сегментируют или эмулируют. Я вообще не понимаю заострения внимания на собственно низлежащей технологии организации локальных фреймов, спор-то зашел не о том, откуда взялся фрейм, а о том, как мы внутри фрейма получаем доступ к локальным переменным. Мои возражения оппоненту по сути сводятся к тому, что принципы работы локальных переменных C# не отличаются особо от других ЯП, предоставляющих локальные переменные, например от Паскаля. Всё равно для программист на высокоуровневом ЯП это прозрачно.
DG>например, stack можно реализовать поверх ассоциативной памяти(ассоциативного массива) — при этом туда-сюда будет меняться имя текущей записи. DG>при этом это все равно будет stack, как структура данных, но это уже не будет тем самым stack-ом, которые используется в яп.
А какой ЯП диктует технику исполнения локальных фреймов? Я че-то и не слышал о таких.
Диктовать может некая архитектура, например x86, бо на ней в конце концов было принято т.н. "соглашение об оформлении фреймов стека для высокоуровневых языков". То, что это соглашение совпадает с тем, как организовывались фреймы стека в компиляторах Pascal от Borland, можно считать совпадением. (бо наблюдал неоднократно в своё время компиляторы, которые организовывали фреймы на x86 иначе, чем Borland и MS)
S>>>Арифметика строится на теории множеств, а не наоборот! Арифметика сложнее теории множеств! DG>>что значит сложнее? формализуй. S>Значит в ней содержится больше утверждений. В теории множеств вводятся только несколько понятий — дизьюнкция, коньюнкция множеств, мощность множества.
S>В арифметике на основе теории множеств вводится множество натуральных чисел и операции с ним.
полная цепочка следующая: теория множеств -> (строится на них) -> абстрактная алгебра -> (выделяется в виде букваря) -> арифметика
при этом арифметика не включает в себя теорию множеств. т.е. арифметика выводится из теории множеств, но не включает ее в себя.
соответственно, утверждать что арифметика сложнее, чем теория множеств нельзя.
DG>>ок. DG>>возьмем "отправить Пинг" и исходную программу. DG>>в какой точке программы Client может считать, что "отправить Пинг" с точки зрения гарантированности доставки выполнено? S>В следующей за вызовом Ping.
т.е. тогда на вариант, когда ответ приходит раньше этого момента — "твое" ООП говорит, что такого не бывает (оно такое не рассматривает)?
DG>>асинхронная пара Ping/Pong с последующей синхронной парой Pong/Pong.return S>То есть Pong является ответом Ping?
да S>А pong.return является ответом на Pong?
да S>Хорошо — а где тогда ответ на Pong в вашем примере?
в исходном? нету. S>И почему вы называете Ping/Pong асинхронной парой?
потому что с точки зрения логического потока управления Client ответ приходит не в тот же момент и не в то же место откуда был послан. S>И что такое r?
в данном случае ничего, потому что не используется.
если используется, то тогда у Ping-а множественный ответ Ping.return и Pong
DG>>тоже самое: асинхронная пара Ping/Pong и синхронная пара Pong/Pong.return DG>>изменилась лишь структура связей (в первом случае, сервер был независим от client-а, сейчас он стал зависимым. S>О, прекрасно. А если у нас будет менее тривиальный граф объектов, и в ответ на Ping() от этого графа нам внезапно придёт с десяток вызовов от разных участников этого графа — то кто из них будет ответом на Ping?
зависит от логики работы. ответом могут быть и все десять, как, например, бывает при broadcast-ах.
DG>>ООП есть универсальный базис для программирования, так же как теория множеств в математике. S>Нет. Никто этого не обещал. Универсальным базисом для программирования являются функции Чёрча или Машина Тьюринга. S>А ООП — это всего лишь модель, удобная для описания каких-то специфических программ.
спорно. Машина тьюринга (и функции Черча) являются больше базисом алгоритмики, а не программирования.
в программирование — кроме алгоритмов, как минимум еще входит моделирование (в полном объеме, или в усеченном — в зависимости от толковании)
а ни в тьюринге, ни в черче нет инструментов моделирования.
S>Просто вики, на которую вы ссылаетесь, не является формальной моделью ООП. Там написан текст для среднестатистического читателя.
уже вроде 5-ый раз говорю: приведи пруфлинк на формальную модель ООП.
ты утверждаешь, что она существует, вот и докажи это, приведя пруфлинк
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>А указатель размещает? S>>Указатель размещает значение, т.к. значением указателя является не то значение, на которое он ссылается, а именно адрес того значения.
V>И как мне получить этот адрес в дотнете из ссылочной переменной? (ты же предположил, что они к указателям ближе)
Я настаиваю, что ближе. Ссылочной переменной можно присваивать новое значение, в точности как указателю. Ну а то что нельзя получить адрес — так дело в том что managed.
V>>>Смотря какой ссылочный. Если тот, который ref в аргументах, то это точная аналогия ссылки С++. S>>Ссылочный тип в дотнете ровно один — тот, чьи экземпляры размещаются в управляемой куче. ref-же является чисто модификатором способа передачи аргумента и не образует нового типа в терминах системы типов дотнета.
V>Гхы......... V>
V> class Program {
V> public void Test(ref int arg) {}
V> static void Main(string[] args) {
V> Console.WriteLine(typeof(Program).GetMethod("Test").GetParameters()[0].ParameterType.Name);
V> }
V> }
V>
V>Что выведет?
Ага, "Int32&". Это я значит штангу толкнул. Тип образуется, но я все равно против того что бы ref называть ссылочным типом. Точнее будет ByRef тип.
V>И кстати, уже можно создавать переменные этого типа в 4-м дотнете, хоть в шарпе пока не поддержали.
Это для меня новость. Но я решительно против называть такую штуку переменной.
S>>В общем, ссылочный тип в C++ был бы тождественнен ref-параметрам дотнета, если бы ECMA не позволяла использовать copy-in/copy-out механизм для ref/out параметров
V>Ну, для случая out-параметров по другому и никак, я же говорил про ref. Допускаю что такое легко обеспечить, коль в дотнете отсутствуют кастомные конструкторы копирования для типов которые могут идти как ref/out, поэтому любая копия гарантированно идентична побитово оригиналу.
Да, для value типов идентичность побитовая по ECMA. Что есть следствие, а что причина — судить не берусь.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>
S>>Так ли это, можно ли назвать i здесь immutable?
S>>В этом контексте Вась (immutable) как минимум двое. Один — значение 123, второй — переменная.
V>123-это литерал, а какое он примет значение, зависит от инициализируемого литералом типа.
А я говорил именно о значении 123, а не о литерале, предполагая что
V>Не представляю, как литерал может быть не-immutable, в исходниках разве что... ведь он живет только в момент компиляции.
Так и переменная живет только в момент компиляции, но может быть как immutable, так и нет. А значит что жизнь во время компиляции тут непричем.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Не продлевает ни разу, ссылки на временный объект нельзя хранить. S>>объявление ссылки на временный объект продлевает жизнь временного объекта до выхода из скопа, в котором определена ссылка. Это не я придумал. Если какой-то компилятор это не выполняет, моя хата с краю.
V>Есть разные виды временных объектов. Если речь про r-value, то на него нельзя получить обычную ссылку, только константную, и я об этом уже говорил. Если же мы получаем ссылку на l-value, то мы заведомо имеем дело не со значением, а со ссылкой, поэтому ничего не продлеваем, а просто запоминаем/делаем копию ссылки.
Я говорю о l-value. Да, пусть константная ссылка. Но она именно "extend the lifetime of a temporary object".
S>>Я о временных объектах, которые создает компилятор на стеке при вычислении выражений, включая приведения типов, вызов функций и т.п. При отсутствии ссылки на такой объект, компилятор волен удалить его сразу после того, как тот перестал быть нужен. А ссылка продляет время жизни такого объекта до выхода из скопа.
V>Опять же, речь о константной ссылке, и она должна быть стековой переменной. Т.е. это не работает, если мы инициализируем ссылкой некий мембер-ссылку.
Не о мемберах, а о временных объектах (я выделил сверху).
V>>>Если адрес взять нельзя, то стадию разыменования адреса мы пропускаем в любом случае. Иначе просто ничего не сойдется. S>>А мы ее итак пропускаем, ведь ссылка — псевдоним объекта, а не указателя на него.
V>Это всего-лишь означает, что этот адрес компилятор разыменовывает за тебя.
Не факт, что адрес вообще есть.
V>>>Гы: V>>>
V>>>int * pi = NULL;
V>>>int & ri = *pi;
V>>>
V>>>Дарю! S>>Да не стоит оно того. Здесь ссылка, кстати, проинициализирована не NULL-ом, а тем int-ом, который получается при разыменовании NULL-а.
V>Нет, именно NULL-ом. *pi не создает копии значения, а приводим напрямую к ссылочному типу. Кстати, этот момент когда-то напрягал в С, бо семантика ссылок в таких точно местах в С используется, а самих ссылок в языке нет. Обрати внимание, выражению *p ты можешь присвоить значение (если в "p" валидный адрес), т.е. тип этого выражения фактически int&, оно же l-value. То, что этот адрес невалидный в этом снипетте никак не влияет на типы.
Возражаю. Тип *(int*) будет int. Усугубим. Возьмем int**, тип *(*(int**)) будет int, а не int&&, согласно твоей логике.
V>>>В общем, в сухом остатке имеем отсутствие operator-> и невозможность взять адрес для обеспечения этого. S>>Ну и область памяти, которая не имеет отношение к значению, если вообще существует.
V>Дык, точно так же как и в случае любых других констант: не факт что занимает память когда в статике или локально, но обязательно занимает, когда является экземплярным мембером. Такие вот в С++ константы.
Адрес константы мы взять можем? А ссылки?
S>>Занимает или не занимает память ссылка — неважно. Важно то, что значение лежит не в той памяти, которую занимает или не занимает ссылка. Значение лежит в памяти переменной (если у той она есть).
V>Значение может и на куче лежать, какие проблемы? Только это уже будет не константа времени компиляции, а константа времени выполнения. В любом случае, то, что ты написал, верно и для констант-указателей.
У константы-указателя можно взять адрес, не?
S>>А я говорил о том что результат компиляции может быть несопоставим с терминами языка, потому решать, что есть переменная (в языке) а что нет, на основании бинарного кода не годится.
V>Для С/С++ это слишком вольное допущение. Он получил популярность именно из-за возможности обеспечить фактически побитовую детерминированность результата. Т.е. абсолютно любой комплятор С++ имеет и специфицированное ABI, и возможность управлять кодогенерацией. А абстрактный стандарт описывает самые общие вещи, независимые от платформ. На этом уровне можно обсуждать что угодно, вплоть до компиляции С++ программы в программу на Лиспе... А что, запросто.
Но переменная — термин языка а не времени выполнения.
S>>Ссылка на переменную оозначает ссылку на значение, хранящееся в переменной.
V>Ну а ссылка на выражение что означает? А если результат выражения не временный, а вполне постоянный?
Если он постоянный, значит у него есть постоянное место. Ссылка на это выражение будет означать ссылку на то место.
S>>А я толкую что мы не определяем будет ли то что написано в исходниках функцией по тому заинлайнит компилятор тело или нет. Так же мы не будем определять что является переменной по результату компиляции.
V>Не, ты не понял. Разное поведение у статический и экземплярных констант потому, что в первом случае под них выделение памяти на усмотрение компилятора (и здесь применимо всё то, что ты сказал), а во втором случае под константу обязательно выделяется память в теле типа-владельца. Ссылки не исключение. Но это очень узко и ничего не объясняет, на самом деле достаточно отличать compile-time константу и runtime константу, тогда твои предположения сойдутся с реальным положением дел. И не только в плане ссылок, а в плане любых констант.
По мне так мои предположения сходятся с реальным положением дел.
Здравствуйте, DarkGray, Вы писали:
DG>мне, кажется, ты упускаешь основной момент: обратное преобразование из msil должно не просто обратно преобразовать в C#, оно еще должна корректно востановить, какие явные преобразования типов можно выкинуть, а какие нельзя. и соответственно оно включает в себя задачу: здесь типы вывести можно или нельзя DG>тот же Reflector кстати с этим периодически ошибается. даже в сложных арифметических выражениях (либо ставит лишние, либо не ставит нужных)
Вопрос вот в чём: является ли программа полученная рефлектором корректной?
Если да, то все претензии — не более чем капризы.
DG>
DG>И чем больше неопределённости семантики мы вносим в язык программирования, тем сложнее становятся задачи проверки корректности программы.
Да.
DG>из своего головы или откуда? опять из букваря?
Конечно же из букваря:
Множество моментов времени T может быть как интервалом вещественной прямой (тогда говорят, что время непрерывно), так и множеством целых или натуральных чисел (дискретное время).
DG>на всякий случай намекну, что в текущий момент в физике не доказано, что время в реальном мире не является дискретным. DG>и что на текущий момент, есть как раз неопределенность — считать реальное время непрерывным или дискретным.
На всякий случай намекну, что этот вопрос не имеет никакого отношения к нашей дискуссии.
DG>как минимум советую вернуться к исходному моему утверждению, и убедиться что там шла речь про отображение одного времени на другое.
Вернулся. Читаю:
допустим локальное время с точки зрения каждого объекта непрерывное
Очевидно, речь идёт про локальное время. Никаких "отображений" и в помине нет.
DG>и что надо передать в эту функцию в качестве объекта, если он спит?
Независимо от того, спит объект или нет, мы передаём ссылку на него.
DG>т.е. пространство оказывается уже есть. уже хорошо. DG>может ли это пространство быть несвязанным? и что про это говорит ООП?
Может и является. См. определение термина связное пространство.
Пространство, в котором каждая компонента связности состоит из одной точки, называется вполне не связным. Примером могут служить любые пространства с дискретной топологией
DG>может ли оно в разные время быть, то связанным, то не связанным?
Не, не может.
DG>это ничего не меняет, потому что ООП не говорит, что отправка сообщения должно занимать один квант времени с точки зрения отправителя.
В ООП отправка атомарна. Это означает, что невозможно наблюдать состояние "1/4 сообщения отправлено". А раз невозможно это наблюдать, то нет смысла говорить о моментах времени "внутри" отправки сообщения.
DG>и с точки зрения объекта целиком кванты времени могут щелкать следующим образом: DG>
DG>1-ый поток: начало кванта отправки сообщения
DG>2-ой поток: раз квант времени
DG>2-ой поток: второй квант времени
DG>2-ой поток: третий квант времени
DG>1-ый поток: конец кванта отправки сообщения
DG>1-ый поток: следующий квант
DG>
Вы по-прежнему не понимаете природы дискретного времени в распределённой системе. Откуда вы знаете, что кванты во втором потоке пронумерованы так, как у вас? Может быть, всё происходит вот так:
1-ый поток: начало кванта отправки сообщения
1-ый поток: конец кванта отправки сообщения
1-ый поток: следующий квант
2-ой поток: раз квант времени
2-ой поток: второй квант времени
2-ой поток: третий квант времени
DG>и во второй ситуации необходимо все-таки разбираться — в какой квант времени считается, что сообщение отправлено DG>зы DG>подчеркну, что логический поток управления лишь примерно соответственно thread-у DG>в примере, который я приводил — там один thread, но два потока управления
Прекратите вводить новые понятия. Вы с предыдущим-то набором ещё не разобрались. Плотность глупостей на параграф уже и так превысила все мыслимые пределы. Когда вы разберётесь с заблуждениями относительно времени и пространства, можно будет перейти к сложным концепциям типа потока управления. Который в вашем примере, конечно же, один.
S>>В частности, это бы приводило к парадоксам вроде получения реакции на сообщение раньше отправки самого сообщения. DG>это тоже требует ООП, чтобы не было таких парадоксов? в каком пункте?
В пункте "поведение объекта зависит от его состояния". Здесь подразумевается, что состояние объекта суть результат его предыдущего поведения. Это, собственно, принцип причинности.
Понимаете, отправка сообщения — это поведение объекта. Допустим, объект А либо отправляет объекту Б сообщение Х, либо нет. В зависимости от своего состояния. Объект Б в ответ отправляет ему сообщение "не надо отправлять мне сообщение X". Когда А получает это сообщение, то он меняет своё состояние так, чтобы в будущем не отправлять таких сообщений. Если это произойдёт раньше, чем он отправит первое сообщение, то Б не станет ему отвечать, и он не получит предупреждение, и отправит сообщение, в ответ на которое Б отправит ответ, который предотвратит отправку вопроса....
Проблема понятна?
DG>потому что для фиксирования каждой неопределенности необходимо весь мир умножить на два: термы, которые будут соответствовать состоянию неопределенности, когда оно находится в состоянии да, и термы, которые будут соответствовать состоянию неопределенности, когда оно находится в состоянии нет. DG>и того получается 2^кол-во неопределенностей
1. Про какие термы мы сейчас говорим?
2. Какой именно параметр вы пытаетесь рассчитать?
3. Откуда взялось возведение в степень?
DG>примерно также как доказывается традиционный алгоритм НОД: DG>для доказательства завершенности: доказывается что каждое следующее состояние не хуже, чем предыдущее, и при этом что рано или поздно для каждого состояние будет переход в более лучшее состояние. DG>для правильности доказывается, что каждый переход между состояниями был легитимным
Ок, у меня есть некоторые сомнения про нюансы, но в целом схему доказательства примем.
вернёмся на шаг назад: в модели с гарантированной доставкой и эмуляцией потерь алгоритм останется корректным, более того — все асимптотики для него сохранятся. Бинго?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>при этом арифметика не включает в себя теорию множеств. т.е. арифметика выводится из теории множеств, но не включает ее в себя.
Ну как это не включает. Вы думаете, можно взять вот так вот и одним махом "упростить" модель, включив в неё другую модель "по ссылке"? DG>соответственно, утверждать что арифметика сложнее, чем теория множеств нельзя.
Можно. Алгебра колец сложнее алгебры абелевых групп.
DG>т.е. тогда на вариант, когда ответ приходит раньше этого момента — "твое" ООП говорит, что такого не бывает (оно такое не рассматривает)?
Почему же? "Точки кода" и "моменты времени" не так однозначно связаны между собой. Вопрос был про точку кода — другой точки в методе нет. Если нет иных событий, то с точки зрения клиента возврат управления происходит в момент времени t+1. А если были — то в момент времени t+N.
DG>потому что с точки зрения логического потока управления Client ответ приходит не в тот же момент и не в то же место откуда был послан.
Ок, то есть термин "синхронность" вы тоже трактуете не так, как все остальные. S>>И что такое r? DG>в данном случае ничего, потому что не используется. DG>если используется, то тогда у Ping-а множественный ответ Ping.return и Pong
Ваша модель неоправданно усложнена. Сервер возвращает клиенту некое число, но оно в вашей модели не является ответом, потому что клиент, видите ли, его не использует. А сервер откуда об этом знает?
S>>О, прекрасно. А если у нас будет менее тривиальный граф объектов, и в ответ на Ping() от этого графа нам внезапно придёт с десяток вызовов от разных участников этого графа — то кто из них будет ответом на Ping?
DG>зависит от логики работы. ответом могут быть и все десять, как, например, бывает при broadcast-ах.
Понятно. Ваша модель неоправданно усложнена; в ней невнятная концепция времени и понятия "ответа на запрос". Чтобы отличить ответ от не-ответа, нужен нетривиальный анализ логики работы (причём вы пока не привели даже примерную схему такого анализа). В общем случае, получается, что любые сообщения, полученные объектом после отправки сообщения M1, являются ответами на это сообщение.
Даже если вам удастся формализовать эту модель, то лично у меня её полезность вызывает серъёзные сомнения.
С учётом того, что существует бесконечно более простые модели описания взаимодействия тех же объектов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>>>А ты вообще про какой стек говоришь? Тот который push\pop или про абстрактную структуру с вложенностью фреймов?
V>>>Ну коль везде говорю про фреймы локальных переменных, то про стек, образованный этими фреймами. Думал и так понятно. Тебе же не приходится каждый раз уточнять про стек в x86 что ты не имел ввиду стек вычислений плавающих регистров x86? Хоть там именно что еще один стек.
G>>Непонятно потому что терминологию низкого уровня ты применяешь для высокоуровневых вещей.
V>Уточни, какой термин тебе показался низкоуровневым?
V>>>Ну так есть байт машина с системой команд, к описанию которой я апеллировал, или таки нет? G>>Да, это все входит в описание CLR. Это ecma-335 + описание IL.
V>Наконец-то. Итак, возвращаясь к началу, оперирует таки байт-машина адресами или нет? Чтобы ты не тратил время, скажу что оперирует.
Чтобы ты правильно понял — не всегда оперирует. Ссылка не адрес.
V>Даже имеет команды перевода адреса в ширину слова данных. Наверно это некий "запас" для тех архитектур (напр. гардвардских), где разрядность адреса не равна разрядности данных. Например, в некоторых PIC-контроллерах адреса имеют 7, 11, 12, 13 и т.д. бит в опкодах. А еще где-то адреса описывают не сплошню память, а сегментированную. А еще где-то адрес всегда относительный, и для целей этого преобразования нужно брать значение базы. Понимаешь, к чему я клоню? Что т.н. "абстракция", на которой вы настаиваете, не только не оторвана от реального мира, наоборот, предоставляет ср-ва, для приведения всевозможных схем к модели "плоской" памяти, которой оперирует байт-машина, коль целевой адрес должен быть непротиворечиво приводим в число прямо по стандарту.
Я думаю тупо для поддержки низкоуровневых языков вроде C++\CLI. Так как все что оперирует адресами — unsafe.
V>>>Вот это номер... Одно из двух, либо невнимательно прочёл приведенный сэмпл, либо вовсе не понимаешь принципов работы value-types в дотнете. В MSDN написано правильно, а ты в 3-х соснах заблудился. причем, в MSDN написано правильно даже для случая ссылочных типов. Надо просто понимать, адрес чего именно загружается на вершину стека вычислений. И таки можно загрузить адрес любой локальной переменной, и потом прочитать в числовом виде значение по этому адресу. Просто у тебя неверное представление, похоже, о происходящем при этом.
G>>Ты опять провалился на тот уровень, который не описывается ecma-335. Ты оперируешь сведениями, доставшимися тебе от C++.
V>Не юли, не убежишь. Ты считал, что описание в MSDN некорректно, и даже исправил его.
Я не исправил, я скопировал тебе строку из remarks
V>Спасибо, теперь хоть понятно, что именно тебе непонятно. Я отсылал тебя к понятию value-type, ты вернулся с тем же представлением... Заметь, речь исключительно о дотнете. Причем тут С++, вообще, если ты показываешь обычное непонимание совсем другого предмета. Ну попроси старших товарищей, которым ты доверяешь, объяснить приведенный мною пример, раз ты не умеешь непредвзято слушать программиста, использующего в числе прочих технологий язык С++.
Это ты не понял что в ecma-335 не написано то что ты рассказываешь. Прочитай внимательно. У тебя банальное представление о CLR, основанное исключительно на твоем unmanaged опыте.
G>>IL работает в терминах абстрактного стека, где "переменная" != адрес и у самих переменных адреса нету. Так что ты опять промахнулся.
V>Да я уже понял твою проблему, не усердствуй... Можно только отослать читать доку до просветления, например тут: V>http://msdn.microsoft.com/ru-ru/library/system.reflection.emit.opcodes.ldfld.aspx V>http://msdn.microsoft.com/ru-ru/library/system.reflection.emit.opcodes.conv_u.aspx
V>Как поймешь написанное, попробуй прочесть опкоды из моего примера еще раз...
Именно ты привел команды чтобы превратить ссылку в unmanaged pointer.
Это как раз означает что ссылка != указатель
Читай ecma-335, там подробно описано.
G>>>>А ты какой стек имеешь ввиду?
V>>>Очевидно из этого: V>>>el = F(frame, index) V>>>имею ввиду тот, в котором живут фреймы (или который ими образован).
G>>Такие "адреса" не предполагают арифметику, так как index вообще говоря не обязан быть числовым.
V>Угу, еще и стандарт был прочитан хотя и многократно, но ни разу полностью.
А теперь ты про стандарт уже говоришь? Ну так в стандарте нет арифметики указателей для стека.
S>Вопрос вот в чём: является ли программа полученная рефлектором корректной? S>Если да, то все претензии — не более чем капризы.
корректности мало. возможность корректности следует из полноты по тьюрингу.
необходимо достичь еще все остальные характеристики
DG>>из своего головы или откуда? опять из букваря? S>Конечно же из букваря: S>
S>Множество моментов времени T может быть как интервалом вещественной прямой (тогда говорят, что время непрерывно),
вот именно, что говорят. это неформальное обозначение. формальное определение из математики я тебе привел вместе с пруфом.
от тебя же пруфа на определение пока еще ни одного не последовало...
DG>>и что надо передать в эту функцию в качестве объекта, если он спит? S>Независимо от того, спит объект или нет, мы передаём ссылку на него.
и что с этой ссылкой делает функция? будит объект?
DG>>т.е. пространство оказывается уже есть. уже хорошо. DG>>может ли это пространство быть несвязанным? и что про это говорит ООП? S>Может и является. См. определение термина связное пространство. S>
S>Пространство, в котором каждая компонента связности состоит из одной точки, называется вполне не связным. Примером могут служить любые пространства с дискретной топологией
DG>>может ли оно в разные время быть, то связанным, то не связанным? S>Не, не может.
S>Вы по-прежнему не понимаете природы дискретного времени в распределённой системе. Откуда вы знаете, что кванты во втором потоке пронумерованы так, как у вас? Может быть, всё происходит вот так:
потому что это один объект, и он может менять свое внутреннее состояние как хочет (это вне модели ООП), и соответственно может передавать информации из одного логического потока управления в другой.
S>>>В частности, это бы приводило к парадоксам вроде получения реакции на сообщение раньше отправки самого сообщения. DG>>это тоже требует ООП, чтобы не было таких парадоксов? в каком пункте? S>В пункте "поведение объекта зависит от его состояния". Здесь подразумевается, что состояние объекта суть результат его предыдущего поведения. Это, собственно, принцип причинности. S>Понимаете, отправка сообщения — это поведение объекта. Допустим, объект А либо отправляет объекту Б сообщение Х, либо нет. В зависимости от своего состояния. Объект Б в ответ отправляет ему сообщение "не надо отправлять мне сообщение X". Когда А получает это сообщение, то он меняет своё состояние так, чтобы в будущем не отправлять таких сообщений. Если это произойдёт раньше, чем он отправит первое сообщение, то Б не станет ему отвечать, и он не получит предупреждение, и отправит сообщение, в ответ на которое Б отправит ответ, который предотвратит отправку вопроса....
S>Проблема понятна?
есть только одна проблема — невозможность в рамках ущербной модели описать конкретное поведение программы.
DG>>потому что для фиксирования каждой неопределенности необходимо весь мир умножить на два: термы, которые будут соответствовать состоянию неопределенности, когда оно находится в состоянии да, и термы, которые будут соответствовать состоянию неопределенности, когда оно находится в состоянии нет. DG>>и того получается 2^кол-во неопределенностей S>1. Про какие термы мы сейчас говорим?
Терм — выражение формального языка (системы), является формальным именем объекта или именем формы. Понятие терма определяется индуктивно. Термом называется символьное выражение: t(X1, X2, … , Xn), где t — имя терма, называемая функтор или «функциональная буква», а X1, X2, … , Xn — термы, структурированные или простейшие.
S>2. Какой именно параметр вы пытаетесь рассчитать?
кол-во термов/утверждений S>3. Откуда взялось возведение в степень?
2*2*2*2 и так n-раз — это есть 2^n
DG>>примерно также как доказывается традиционный алгоритм НОД: DG>>для доказательства завершенности: доказывается что каждое следующее состояние не хуже, чем предыдущее, и при этом что рано или поздно для каждого состояние будет переход в более лучшее состояние. DG>>для правильности доказывается, что каждый переход между состояниями был легитимным S>Ок, у меня есть некоторые сомнения про нюансы, но в целом схему доказательства примем. S>вернёмся на шаг назад: в модели с гарантированной доставкой и эмуляцией потерь алгоритм останется корректным, более того — все асимптотики для него сохранятся. Бинго?
асимптотики не сохраняются прежде всего по размеру самого алгоритма. а отсюда ползет несохранение и всяких следствий из этого.
S>С учётом того, что существует бесконечно более простые модели описания взаимодействия тех же объектов.
почти нет моделей, которые позволяют описывать эквивалентность моделей(кода).
а МП появляется только если у нас есть возможность указать: какие куски кода эквиваленты, и какой из них лучше.
Здравствуйте, DarkGray, Вы писали:
DG>корректности мало. возможность корректности следует из полноты по тьюрингу. DG>необходимо достичь еще все остальные характеристики
Какие именно?
DG>вот именно, что говорят. это неформальное обозначение. формальное определение из математики я тебе привел вместе с пруфом. DG>от тебя же пруфа на определение пока еще ни одного не последовало...
Я дал ссылку на формальное определение. Но вы, я вижу, не понимаете разницы между понятиями "непрерывное множество" и "непрерывное отображение".
На этом, я думаю, дискуссию можно завершить. С клиническими случаями я справиться неспособен.
DG>и что с этой ссылкой делает функция? будит объект?
Я показал, что делает функция. Выполняет сравнение ссылок.
DG>кол-во термов/утверждений S>>3. Откуда взялось возведение в степень? DG>2*2*2*2 и так n-раз — это есть 2^n
Непонятно, откуда берётся умножение в вашей формуле. Если у вас добавление ждого объекта с N состояниями автоматически увеличивает количество термов в N раз, то ваша модель утонет задолго до того, как мы добавим в неё объекты — переходники.
DG>асимптотики не сохраняются прежде всего по размеру самого алгоритма. а отсюда ползет несохранение и всяких следствий из этого.
С чего бы это? Сам алгоритм никак не изменится.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>почти нет моделей, которые позволяют описывать эквивалентность моделей(кода).
Просто удивительно — как же Чёрч с Тьюрингом ухитрились договориться.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Lloyd, Вы писали:
L>Вы говорите хорошие и правильные слова, которые вряд ли кто возьмется оспаривать. L>Но они не имеют никакого отношения к моей реплике, на которую вы взялись отвечать. Совсем никакого.
А я и ответил не на одну реплику, а когда созрел по прочтении части ветки. Вы сравнивали теплое с мягким в обсуждении: ООП с ссылочным типом.
Дык, даже ссылочные типы очень разные, даже в дотнете. Зато способы адресации — универсальны, т.е. в их терминах можно выразить любой способ доступа к объектам в любой ООП-программе. Вот и попытался напомнить, что обсуждать/вспомнить разновидности адресации имеет смысл, а приписывать ООП нечто особенное в этом плане — нет.
Здравствуйте, samius, Вы писали:
V>>Не представляю, как литерал может быть не-immutable, в исходниках разве что... ведь он живет только в момент компиляции. S>Так и переменная живет только в момент компиляции, но может быть как immutable, так и нет. А значит что жизнь во время компиляции тут непричем.
Наоборот, переменная живет и рантайм. (кроме случаев оптимизации компилятором)
Наверно ты имел ввиду, что символьное имя переменной в рантайм не живет? Но это не то же, что переменная. Просто символьный идентификатор в процессе компиляции (или линковки) заменяется некий конкретный вид адресации с некоторой фиксированной (обязательно!) составляющей. Вот эта фиксированная составляющая и отличает одну переменную от другой даже в рантайме. В этом плане мало что изменилось со времен переменных в ассемблере, разве что системы типов побогаче, чем в инструкциях db, dw, dd, dq.
Здравствуйте, vdimas, Вы писали:
L>>Вы говорите хорошие и правильные слова, которые вряд ли кто возьмется оспаривать. L>>Но они не имеют никакого отношения к моей реплике, на которую вы взялись отвечать. Совсем никакого.
V>А я и ответил не на одну реплику, а когда созрел по прочтении части ветки.
Т.е. ваш ответ не исеет отношения к посту, на который вы отвечали?
Пост из одной реплики и состоял.
V>Вы сравнивали теплое с мягким в обсуждении: ООП с ссылочным типом.
В моих постах не было упоминания ни ООП, ни ссылочных типов.
V>Дык, даже ссылочные типы очень разные, даже в дотнете. Зато способы адресации — универсальны, т.е. в их терминах можно выразить любой способ доступа к объектам в любой ООП-программе. Вот и попытался напомнить, что обсуждать/вспомнить разновидности адресации имеет смысл, а приписывать ООП нечто особенное в этом плане — нет.
А я попытался вам намекнуть, что неплохо бы читать пост, на который отвечаете. Никаких таких ужасов, которые вы мне приписываете, в том посте не содержалось.
Здравствуйте, gandjustas, Вы писали:
V>>Наконец-то. Итак, возвращаясь к началу, оперирует таки байт-машина адресами или нет? Чтобы ты не тратил время, скажу что оперирует. G>Чтобы ты правильно понял — не всегда оперирует. Ссылка не адрес.
Уже "не всегда"?
Ну хоть какие-то подвижки... А то, что переменная ссылочного типа — это такая же переменная как и любая другая и что е адрес тоже можно взять (не адрес объекта, а именно адрес переменной) будем опять обсуждать или уже и так понял?
V>>Даже имеет команды перевода адреса в ширину слова данных. Наверно это некий "запас" для тех архитектур (напр. гардвардских), где разрядность адреса не равна разрядности данных. Например, в некоторых PIC-контроллерах адреса имеют 7, 11, 12, 13 и т.д. бит в опкодах. А еще где-то адреса описывают не сплошню память, а сегментированную. А еще где-то адрес всегда относительный, и для целей этого преобразования нужно брать значение базы. Понимаешь, к чему я клоню? Что т.н. "абстракция", на которой вы настаиваете, не только не оторвана от реального мира, наоборот, предоставляет ср-ва, для приведения всевозможных схем к модели "плоской" памяти, которой оперирует байт-машина, коль целевой адрес должен быть непротиворечиво приводим в число прямо по стандарту. G>Я думаю тупо для поддержки низкоуровневых языков вроде C++\CLI. Так как все что оперирует адресами — unsafe.
Да нет никаких отдельных инструкций unsafe. Иди изучай стандарт и медитируй над сниппетом. Абсолютно одни и те же опкоды используются что для unsafe вызова, что для safe. А вот что чем является это можно выяснить только во время верификации, но никак по каким-то особенным инструкциям "для поддержки низкоуровневых языков". Я уже давал ссылки на доку по опкодам, оперирующим адресами. Эти опкоды встречаются в теле абсолютно нормальных safe программ.
V>>Не юли, не убежишь. Ты считал, что описание в MSDN некорректно, и даже исправил его.
G>Я не исправил, я скопировал тебе строку из remarks
G>Это ты не понял что в ecma-335 не написано то что ты рассказываешь. Прочитай внимательно. У тебя банальное представление о CLR, основанное исключительно на твоем unmanaged опыте.
Написано, прочти стандарт хоть раз до конца.
G>А теперь ты про стандарт уже говоришь?
Ну так ты же начал к нему аппелировать, пусть так. Давай на твоем "поле" поиграем, мне без разницы.
G>Ну так в стандарте нет арифметики указателей для стека.
"арифметика указателей для стека" — это несвязанный набор символов. В стандарте есть оперирование адресами, и опровержение таких твоих фантазий:
index вообще говоря не обязан быть числовым.
И адресная арифметика, надо сказать, тоже есть. Когда поймешь как работает приведенный здесь
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Не представляю, как литерал может быть не-immutable, в исходниках разве что... ведь он живет только в момент компиляции. S>>Так и переменная живет только в момент компиляции, но может быть как immutable, так и нет. А значит что жизнь во время компиляции тут непричем.
V>Наоборот, переменная живет и рантайм. (кроме случаев оптимизации компилятором) V>Наверно ты имел ввиду, что символьное имя переменной в рантайм не живет? Но это не то же, что переменная. Просто символьный идентификатор в процессе компиляции (или линковки) заменяется некий конкретный вид адресации с некоторой фиксированной (обязательно!) составляющей. Вот эта фиксированная составляющая и отличает одну переменную от другой даже в рантайме. В этом плане мало что изменилось со времен переменных в ассемблере, разве что системы типов побогаче, чем в инструкциях db, dw, dd, dq.
То определение переменной, на которое ты ссылался, утверждает что переменная и есть символическое имя.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>Наконец-то. Итак, возвращаясь к началу, оперирует таки байт-машина адресами или нет? Чтобы ты не тратил время, скажу что оперирует. G>>Чтобы ты правильно понял — не всегда оперирует. Ссылка не адрес.
V>Уже "не всегда"? V>Ну хоть какие-то подвижки... А то, что переменная ссылочного типа — это такая же переменная как и любая другая и что е адрес тоже можно взять (не адрес объекта, а именно адрес переменной) будем опять обсуждать или уже и так понял?
Ты почитай спеку, нельзя адрес переменной взять.
V>>>Даже имеет команды перевода адреса в ширину слова данных. Наверно это некий "запас" для тех архитектур (напр. гардвардских), где разрядность адреса не равна разрядности данных. Например, в некоторых PIC-контроллерах адреса имеют 7, 11, 12, 13 и т.д. бит в опкодах. А еще где-то адреса описывают не сплошню память, а сегментированную. А еще где-то адрес всегда относительный, и для целей этого преобразования нужно брать значение базы. Понимаешь, к чему я клоню? Что т.н. "абстракция", на которой вы настаиваете, не только не оторвана от реального мира, наоборот, предоставляет ср-ва, для приведения всевозможных схем к модели "плоской" памяти, которой оперирует байт-машина, коль целевой адрес должен быть непротиворечиво приводим в число прямо по стандарту. G>>Я думаю тупо для поддержки низкоуровневых языков вроде C++\CLI. Так как все что оперирует адресами — unsafe.
V>Да нет никаких отдельных инструкций unsafe.
Есть, читай Exca-335
V>Иди изучай стандарт и медитируй над сниппетом. Абсолютно одни и те же опкоды используются что для unsafe вызова, что для safe. А вот что чем является это можно выяснить только во время верификации, но никак по каким-то особенным инструкциям "для поддержки низкоуровневых языков".
А как верификация выполнятеся? IL ведь анализируется.
V>Я уже давал ссылки на доку по опкодам, оперирующим адресами. Эти опкоды встречаются в теле абсолютно нормальных safe программ.
Ты как-то опкоды рассматриваешь отдельно от системы типов, но IL это не ассемблер, там еще и типы есть. Так вод один опкоды будут safe для работы с одними типами, и те же unsafe.
V>>>Не юли, не убежишь. Ты считал, что описание в MSDN некорректно, и даже исправил его.
G>>Я не исправил, я скопировал тебе строку из remarks
V>Здесь? http://www.rsdn.ru/forum/philosophy/4509932.1.aspx
The stack transitional behavior, in sequential order, is:
The address stored in the local variable at the specified index is pushed onto the stack.
Не знаю какая каша и где она у тебя, но ты определенно видишь то что хочешь видеть, но не хочешь читать.
Ты сам то читал полностью то на что ссылаешься? Только на английском яызыке прочти, русский зачастую неточен.
G>>Это ты не понял что в ecma-335 не написано то что ты рассказываешь. Прочитай внимательно. У тебя банальное представление о CLR, основанное исключительно на твоем unmanaged опыте. V>Написано, прочти стандарт хоть раз до конца.
Ну приведи раздел, параграф.
G>>А теперь ты про стандарт уже говоришь? V>Ну так ты же начал к нему аппелировать, пусть так. Давай на твоем "поле" поиграем, мне без разницы.
Конечно тебе без разницы, потому что ты его не читал. Отдыхай.
G>>Ну так в стандарте нет арифметики указателей для стека.
V>"арифметика указателей для стека" — это несвязанный набор символов. В стандарте есть оперирование адресами, и опровержение таких твоих фантазий: V>
V>index вообще говоря не обязан быть числовым.
Так ты всетаки про стек CLR или про el=F(frame,index) ? Я говорил про второе.
V>И адресная арифметика, надо сказать, тоже есть.
Есть, но она не имеет никакого отношения к переменным ссылочного типа.
Здравствуйте, samius, Вы писали:
V>>[/c#] V>>Что выведет? S>Ага, "Int32&". Это я значит штангу толкнул. Тип образуется, но я все равно против того что бы ref называть ссылочным типом. Точнее будет ByRef тип.
Разве by ref не есть "по ссылке"? Этот термин из VB, и там by ref означает ссылочный тип, который в терминах С++/COM мапится на указатели.
V>>И кстати, уже можно создавать переменные этого типа в 4-м дотнете, хоть в шарпе пока не поддержали. S>Это для меня новость. Но я решительно против называть такую штуку переменной.
Признаюсь, через все топики так и не понял — почему? Ведь нельзя же предположить, что всё само собой работает "чудесным" образом. На примере С++ я показал, что бывают ссылки, которые ссылаются на адрес времени компиляции, и тогда этих "ссылок-переменных" может не быть, коль речь идет о константе, а бывают те, которые инициализируются по адресу, известному только в рантайм. Причем, обе ситуации в исходном коде отличаются безошибочно, не спутаешь (кроме особого случая ссылок как членов других составных типов). Так вот, второй способ априори требует некоей памяти для хранения представления ссылки, ведь всё происходит динамически. В дотнете аналогично, с той разницей, что GC может двигать адреса, но ведь это для нас это прозрачно... Итого, в рантайм получаем ссылку на некое поле другого объекта, и, т.к. это значение времени исполнения, внутреннее представление ссылки (будь оно хоть чем) надо где-то хранить. Сдается мне, этот "где-то" попадает под определение "переменная".
S>>>В общем, ссылочный тип в C++ был бы тождественнен ref-параметрам дотнета, если бы ECMA не позволяла использовать copy-in/copy-out механизм для ref/out параметров
V>>Ну, для случая out-параметров по другому и никак, я же говорил про ref. Допускаю что такое легко обеспечить, коль в дотнете отсутствуют кастомные конструкторы копирования для типов которые могут идти как ref/out, поэтому любая копия гарантированно идентична побитово оригиналу. S>Да, для value типов идентичность побитовая по ECMA. Что есть следствие, а что причина — судить не берусь.
Ну... глядя на функциональность СomponentModel, например, хорошо видно, что первопричиной была реализация функциональности и визуального дизайна исключительно WinForms.
А копирование value-type, в том числе значений ссылочного типа, взято на себя платформой, ИМХО, по причине автоматизации сериализации (для целей ремоутинга в т.ч.). Именно так ref/out сохраняют семантику даже при копировании, что позволило сделать remouting не в пример проще в реализации и прозрачнее в использовании, например, чем в джавовском RMI.
Здравствуйте, samius, Вы писали:
V>>Наоборот, переменная живет и рантайм. (кроме случаев оптимизации компилятором) V>>Наверно ты имел ввиду, что символьное имя переменной в рантайм не живет? Но это не то же, что переменная. Просто символьный идентификатор в процессе компиляции (или линковки) заменяется некий конкретный вид адресации с некоторой фиксированной (обязательно!) составляющей. Вот эта фиксированная составляющая и отличает одну переменную от другой даже в рантайме. В этом плане мало что изменилось со времен переменных в ассемблере, разве что системы типов побогаче, чем в инструкциях db, dw, dd, dq. S>То определение переменной, на которое ты ссылался, утверждает что переменная и есть символическое имя.
Я ссылался на определение, что переменная — это именованная область памяти, что есть тоже самое, что и алиас/синоним некоего представления (пусть числового) адреса этой области. Я просто обратил внимание, что имя-то в процессе компиляции/линковки уйдет, а область памяти — нет, будь оно хоть чем: глобальной областью, локальной или полем другого объекта.
Здравствуйте, gandjustas, Вы писали:
V>>Ну хоть какие-то подвижки... А то, что переменная ссылочного типа — это такая же переменная как и любая другая и что е адрес тоже можно взять (не адрес объекта, а именно адрес переменной) будем опять обсуждать или уже и так понял? G>Ты почитай спеку, нельзя адрес переменной взять.
Это уже клиника натуральная...
Чем отличаются инструкции ldloc и ldloca?
G>Есть, читай Exca-335
После случая несколькими постами выше позволю себе игнорировать твое аппелирование к стандарту, ты читал только вводную часть.
V>>Абсолютно одни и те же опкоды используются что для unsafe вызова, что для safe. А вот что чем является это можно выяснить только во время верификации, но никак по каким-то особенным инструкциям "для поддержки низкоуровневых языков". G> А как верификация выполнятеся? IL ведь анализируется.
Ну так в рантайм во время загрузки, играет рояль не только опкоды, но сама последовательность операций. Состояние дотнетной стек-машины обязательно детерминировано (иначе верификация невозможна, выдает ошибку). Детерминировано, это значит, верификатор достоверно знает, в каждый момент времени типы объектов, находящихся на стеке вычислений. Именно так и происходит типизация. Вот простейший пример: в опкодах идет код загрузки на вершину стека вычислений адреса одного из объектов известного верификатору типа, а следом вызывается метод, определенный в другом типе из другой сборки. Загрузчику приходится подгружать зависимые сборки и только после этого верификатор сможет увидеть, является ли тип одного объекта транзитивно подтипом другого. Т.е. является ли такой вызов типобезопасным.
Поэтому, когда я пишу:
Абсолютно одни и те же опкоды используются что для unsafe вызова, что для safe. А вот что чем является это можно выяснить только во время верификации
Это означает, что только во время верификации можно достоверно узнать, что на вершине стека не просто целочисленное значение, а именно unmanaged-адрес объекта конкретного типа. Для несложных сценариев такую верификацию можно проделать и в уме, пройдясь по листингу. Как в раз в приведенном примере самое то для устной верификации.
G>
G>The stack transitional behavior, in sequential order, is:
G>The address stored in the local variable at the specified index is pushed onto the stack.
G>Не знаю какая каша и где она у тебя, но ты определенно видишь то что хочешь видеть, но не хочешь читать.
И? Разве не увидел расхождений на той же странице с этим:
Loads the address of the local variable at a specific index onto the evaluation stack.
Loads the address of the local variable at index onto the evaluation stack.
The ldloca instruction pushes the address of the local variable number at the passed index onto the stack, where local variables are numbered 0 onwards. The value pushed on the stack is already aligned correctly for use with instructions like Ldind_I and Stind_I. The result is a transient pointer (type *).
А для разрешения противоречий можно сходить по адресу Ldind_I and Stind_I и посмотреть, что они делают:
Stores a value of type native int at a supplied address.
Итого, можно погрузить на стек адрес, например, некоей переменной int32, а затем косвенно по этому адресу поместить значение. Для полноты картины можно нарисовать прогу в опкодах из 4-х строчек и убедиться самому.
Ну и самое главное, у тебя же перед глазами исходник на C#, ты должен уметь читать код. Нет там нигде никакого адреса в переменной перед первой инструкцией ldloca.
G>>>Ну так в стандарте нет арифметики указателей для стека.
V>>"арифметика указателей для стека" — это несвязанный набор символов. В стандарте есть оперирование адресами, и опровержение таких твоих фантазий: V>>
V>>index вообще говоря не обязан быть числовым.
G>Так ты всетаки про стек CLR или про el=F(frame,index) ? Я говорил про второе.
Что опять???
Давай завязывать. Откуда берется фрейм — уже выясили. Откуда берется index — тоже только что выяснили. Ты сходил до стандарта? Убедился, что тебя не обманывали? Всё предельно ясно.
V>>И адресная арифметика, надо сказать, тоже есть. G>Есть, но она не имеет никакого отношения к переменным ссылочного типа.
А это причем? Да и зачем мне unmanaged-адрес ссылочного объекта, если есть точно такой же managed, но! для случая unmanaged нам недоступна структура объекта, как он хранится на куче, бо она отдается на откуп реализации. Что я буду делать с этим адресом? Например, мне не нужен объект-строка целиком, мне нужен адрес первого символа в буфере строки, если уж речь об указателях, — и я могу это получить. Или мне нужен адрес первого элемента value-типа в массиве — без проблем. Но мне не нужен сам адрес массива, я же не знаю, как он устроен, правильно? Ниже в примере берется адрес поля managed-объекта в куче — вот это без проблем, потому как это адрес известной мне структуры — Int32.
class Program {
class P1 { public int i; }
unsafe static void Main(string[] args) {
var p1 = new P1();
fixed (int* ptr = &p1.i)
*ptr = 42;
Console.WriteLine(p1.i);
}
}
Здравствуйте, samius, Вы писали:
S>Возражаю. Тип *(int*) будет int. Усугубим. Возьмем int**, тип *(*(int**)) будет int, а не int&&, согласно твоей логике.
Дык, тип int& компилятором тоже воспринимается в выражениях как int, когда rvalue. Я же акцентировал выше. Если это r-value, то это int, даже если исходный тип был явно определенный int&, а если это l-value — то это семантика ссылочного типа, точно такая же, как у обычной ссылки. Помнишь я сетовал, что у обычного С семантика ссылок есть, это l-value, а самих сылок нет.
V>>>>В общем, в сухом остатке имеем отсутствие operator-> и невозможность взять адрес для обеспечения этого. S>>>Ну и область памяти, которая не имеет отношение к значению, если вообще существует.
V>>Дык, точно так же как и в случае любых других констант: не факт что занимает память когда в статике или локально, но обязательно занимает, когда является экземплярным мембером. Такие вот в С++ константы. S>Адрес константы мы взять можем? А ссылки?
Косвенно разве что.
Есть такой прием, называется — "оборачивание ссылок". Этот прием пользуется тем, что под ссылку-мембер всегда выделяют память, поэтому можно сделать структуру с одним полем — ссылкой, и оперировать этой структурой как обычным значением.
S>>>Занимает или не занимает память ссылка — неважно. Важно то, что значение лежит не в той памяти, которую занимает или не занимает ссылка. Значение лежит в памяти переменной (если у той она есть).
V>>Значение может и на куче лежать, какие проблемы? Только это уже будет не константа времени компиляции, а константа времени выполнения. В любом случае, то, что ты написал, верно и для констант-указателей. S>У константы-указателя можно взять адрес, не?
И?
Ты опять сравниваешь список операций НАД переменными ссылочных типов, используя это как аргумент, когда утверждалось, что эти ссылочные типы практически идентичны по семантике, когда речь идет о доступе к целевому значению (т.е. того, на которые ссылается этот ссылочный тип). Так можно долго ходить по кругу, возражая, что холодильник прямоугольный, а вовсе не белый.
Ну конечно, если ссылочные типы разные, и то и разный набор операций над ними. Ссылка, в отличие от константного указателя, может иметь всего один уровень косвенности. Т.е. ссылка на ссылку невозможна. Если нам необходимы дополнительные уровни косвенности, то берем в таких сценариях указатели, какие проблемы?
На мой взгляд, отсутствие operator-> и невозможность взять адреса — абсолютно комплиментарны для ссылок, ведь определение operator-> искуственное и "натянутое" (синтаксиса ради), т.к. он возвращает указатель, к которому опять применяется operator->. Т.е. для встроенных указателей это был бы бесконечный рекурсивный вызов. А его нет. Это особый случай. Или наоборот, особым можно считать случай переопределенного operator-> у пользовательских типов, как угодно. Но это разные семантически вещи под одним синтаксисом, данным нам удобства ради. Так вот, будем рассматривать применение operator-> к ссылке. Например, ты можешь иметь ссылку и укзатель на тип, который, в свою очередь имеет operator->, например:
Т.е. мы просто убираем всю эту мишуру с разыменованием адреса для ссылки:
(*tmpPtr)->XXX(), заменяя на более читабельное tmpRef->XXX();
Но ведь operator-> у ссылки не определен!
Вот и все срослось. Ссылка — это синтаксический сахар над константным указателем, где разыменование адреса за нас делает ВСЕГДА делает компилятор. Т.е., обращаясь к ссылке, у нас обязательно идет разыменование ссылочного типа и оперирование целевым значением.
А раз так, то допустимая операция взятия адреса операция &tmpRef, после подстановки указателя будет выглядеть так:
&(*ptrRef);
Видишь, унарный operator& применяется не к самому ссылочному типу, а сразу к целевому, указуемому/ссылаемому полученному после разыменования. Итого, адрес у ссылки нельзя взять потому, что синтаксическая конструкция взятия адреса относится в случае ссылки к целевому объекту, а не к самой ссылочной переменной. Как и все остальные операторы, тот же operator->, который теперь относится к целевому объекту, а не ссылке. Круг замкнулся.
S>По мне так мои предположения сходятся с реальным положением дел.
Не сходятся в случае ссылок как экземплярных полей.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>[/c#] V>>>Что выведет? S>>Ага, "Int32&". Это я значит штангу толкнул. Тип образуется, но я все равно против того что бы ref называть ссылочным типом. Точнее будет ByRef тип.
V>Разве by ref не есть "по ссылке"? Этот термин из VB, и там by ref означает ссылочный тип, который в терминах С++/COM мапится на указатели.
Я не знаю VB и VB.NET, но знаю что передача по ссылке в дотнете никак не связана с COM.
V>>>И кстати, уже можно создавать переменные этого типа в 4-м дотнете, хоть в шарпе пока не поддержали. S>>Это для меня новость. Но я решительно против называть такую штуку переменной.
V>Признаюсь, через все топики так и не понял — почему? Ведь нельзя же предположить, что всё само собой работает "чудесным" образом. На примере С++ я показал, что бывают ссылки, которые ссылаются на адрес времени компиляции, и тогда этих "ссылок-переменных" может не быть, коль речь идет о константе, а бывают те, которые инициализируются по адресу, известному только в рантайм. Причем, обе ситуации в исходном коде отличаются безошибочно, не спутаешь (кроме особого случая ссылок как членов других составных типов). Так вот, второй способ априори требует некоей памяти для хранения представления ссылки, ведь всё происходит динамически. В дотнете аналогично, с той разницей, что GC может двигать адреса, но ведь это для нас это прозрачно... Итого, в рантайм получаем ссылку на некое поле другого объекта, и, т.к. это значение времени исполнения, внутреннее представление ссылки (будь оно хоть чем) надо где-то хранить. Сдается мне, этот "где-то" попадает под определение "переменная".
Я уже припух объяснять, что значение переменной типа указателя — есть указатель и он хранится в памяти, отведенной для переменной. Значение "переменной" типа ссылка хранится в другом месте, чем хранится внутреннее представление ссылки. При этом, нет возможности (легальной) взять адрес внутреннего представления ссылки и как-то повлиять на его содержимое.
S>>Да, для value типов идентичность побитовая по ECMA. Что есть следствие, а что причина — судить не берусь.
V>Ну... глядя на функциональность СomponentModel, например, хорошо видно, что первопричиной была реализация функциональности и визуального дизайна исключительно WinForms.
V>А копирование value-type, в том числе значений ссылочного типа, взято на себя платформой, ИМХО, по причине автоматизации сериализации (для целей ремоутинга в т.ч.). Именно так ref/out сохраняют семантику даже при копировании, что позволило сделать remouting не в пример проще в реализации и прозрачнее в использовании, например, чем в джавовском RMI.
Возможно
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Наоборот, переменная живет и рантайм. (кроме случаев оптимизации компилятором) V>>>Наверно ты имел ввиду, что символьное имя переменной в рантайм не живет? Но это не то же, что переменная. Просто символьный идентификатор в процессе компиляции (или линковки) заменяется некий конкретный вид адресации с некоторой фиксированной (обязательно!) составляющей. Вот эта фиксированная составляющая и отличает одну переменную от другой даже в рантайме. В этом плане мало что изменилось со времен переменных в ассемблере, разве что системы типов побогаче, чем в инструкциях db, dw, dd, dq. S>>То определение переменной, на которое ты ссылался, утверждает что переменная и есть символическое имя.
V>Я ссылался на определение, что переменная — это именованная область памяти, что есть тоже самое, что и алиас/синоним некоего представления (пусть числового) адреса этой области. Я просто обратил внимание, что имя-то в процессе компиляции/линковки уйдет, а область памяти — нет, будь оно хоть чем: глобальной областью, локальной или полем другого объекта.
Я не настаиваю на точности определения, но раз оно говорит что переменная — это именованная область памяти, а имени в рантайме нет, то значит согласно этому определению, в рантайме нет переменной.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Возражаю. Тип *(int*) будет int. Усугубим. Возьмем int**, тип *(*(int**)) будет int, а не int&&, согласно твоей логике.
V>Дык, тип int& компилятором тоже воспринимается в выражениях как int, когда rvalue. Я же акцентировал выше. Если это r-value, то это int, даже если исходный тип был явно определенный int&, а если это l-value — то это семантика ссылочного типа, точно такая же, как у обычной ссылки. Помнишь я сетовал, что у обычного С семантика ссылок есть, это l-value, а самих сылок нет.
V>Вот нашел ссылку, подробно Павел когда-то расписал: http://www.rsdn.ru/forum/cpp/141873.1.aspx
За ссылку спасибо, но это ничего не доказывает в обсуждаемом предмете.
V>>>Дык, точно так же как и в случае любых других констант: не факт что занимает память когда в статике или локально, но обязательно занимает, когда является экземплярным мембером. Такие вот в С++ константы. S>>Адрес константы мы взять можем? А ссылки?
V>Косвенно разве что. V>Есть такой прием, называется — "оборачивание ссылок". Этот прием пользуется тем, что под ссылку-мембер всегда выделяют память, поэтому можно сделать структуру с одним полем — ссылкой, и оперировать этой структурой как обычным значением.
Косвенно и не для каждой ссылки
V>>>Значение может и на куче лежать, какие проблемы? Только это уже будет не константа времени компиляции, а константа времени выполнения. В любом случае, то, что ты написал, верно и для констант-указателей. S>>У константы-указателя можно взять адрес, не?
V>И? V>Ты опять сравниваешь список операций НАД переменными ссылочных типов, используя это как аргумент, когда утверждалось, что эти ссылочные типы практически идентичны по семантике, когда речь идет о доступе к целевому значению (т.е. того, на которые ссылается этот ссылочный тип). Так можно долго ходить по кругу, возражая, что холодильник прямоугольный, а вовсе не белый.
Так он ведь прямоугольный...
V>Ну конечно, если ссылочные типы разные, и то и разный набор операций над ними. Ссылка, в отличие от константного указателя, может иметь всего один уровень косвенности. Т.е. ссылка на ссылку невозможна. Если нам необходимы дополнительные уровни косвенности, то берем в таких сценариях указатели, какие проблемы?
никаких. V>На мой взгляд, отсутствие operator-> и невозможность взять адреса — абсолютно комплиментарны для ссылок, ведь определение operator-> искуственное и "натянутое" (синтаксиса ради), т.к. он возвращает указатель, к которому опять применяется operator->. Т.е. для встроенных указателей это был бы бесконечный рекурсивный вызов. А его нет. Это особый случай. Или наоборот, особым можно считать случай переопределенного operator-> у пользовательских типов, как угодно. Но это разные семантически вещи под одним синтаксисом, данным нам удобства ради. Так вот, будем рассматривать применение operator-> к ссылке. Например, ты можешь иметь ссылку и укзатель на тип, который, в свою очередь имеет operator->, например: V>
V>Т.е. мы просто убираем всю эту мишуру с разыменованием адреса для ссылки: V>(*tmpPtr)->XXX(), заменяя на более читабельное tmpRef->XXX();
V>Но ведь operator-> у ссылки не определен!
и что? V>Вот и все срослось. Ссылка — это синтаксический сахар над константным указателем, где разыменование адреса за нас делает ВСЕГДА делает компилятор. Т.е., обращаясь к ссылке, у нас обязательно идет разыменование ссылочного типа и оперирование целевым значением.
То что ссылка есть синтаксический сахар над константным указателем — возражать не будут. Но это не заставляет меня думать о ссылке как о переменной.
V>А раз так, то допустимая операция взятия адреса операция &tmpRef, после подстановки указателя будет выглядеть так: V>&(*ptrRef); V>Видишь, унарный operator& применяется не к самому ссылочному типу, а сразу к целевому, указуемому/ссылаемому полученному после разыменования. Итого, адрес у ссылки нельзя взять потому, что синтаксическая конструкция взятия адреса относится в случае ссылки к целевому объекту, а не к самой ссылочной переменной. Как и все остальные операторы, тот же operator->, который теперь относится к целевому объекту, а не ссылке. Круг замкнулся.
Замкнулся уже который раз, но ничего не изменилось в отношении того является ли ссылка переменной.
S>>По мне так мои предположения сходятся с реальным положением дел.
V>Не сходятся в случае ссылок как экземплярных полей.
Ссылка -экземплярное поле, ровно как и обычная ссылка, не хранит значение, на которое ссылается. Но хранит служебную информацию, позволяющую находить это значение, в точности как указатель. Однако, тип переменной указателя — указатель, и переменная указатель хранит свое значение (указатель). А ссылка — это сахар.
Здравствуйте, samius, Вы писали:
S>Я не знаю VB и VB.NET, но знаю что передача по ссылке в дотнете никак не связана с COM.
Таки связана. Где требуется COM interop и по сигнатуре идет указатель на структуру, там ты можешь передать ссылочный тип, либо же value-тип, но через модификатор ref, чтобы получить такой же уровень индирекции.
S>Я уже припух объяснять, что значение переменной типа указателя — есть указатель и он хранится в памяти, отведенной для переменной. Значение "переменной" типа ссылка хранится в другом месте, чем хранится внутреннее представление ссылки. При этом, нет возможности (легальной) взять адрес внутреннего представления ссылки и как-то повлиять на его содержимое.
Ну... Это пошла сугубо философия, не имеющая отношение к реально происходящему, в дебри которой я лезть всё равно не стану. Из того факта, что ты не можешь узнать устройство ссылки, ты делаешь слишком далекоидущие выводы. Меня, как программиста, вообще не должно интересовать ничего, кроме уровня косвенности в каждом конкретном случае, потому что косвенное обращение само по себе и есть основа гибкости и повторного использования одного и того же кода для разных экземпляров объектов/значений. И в этом плане, как управляемые ссылки дотнета (т.е. аналоги указателей С/С++), так и ссылки на мемберы или члены стека (т.е. аналоги ссылок в С++) демонстрируют одни и те же характеристики для программиста... Особенно, если не стоит задача узнать устройство ссылки... Важно лишь это — создание копии ссылки не есть создание копии целевого объекта/значения, и как следствие: несколько ссылок может ссылаться на один объект/значение, или же один и тот же аргумент-ссылка может ссылаться на разные объекты/значения в разных вызовах. А остальное непринципиально.
В общем, я такими вещами не заморачиваюсь и могу, разве что, опять отослать к способам адресации. Только так можно не заблудиться в "Философии". Потому как алгоритмы (просто алгоритмы, без привязки к языку) именно подразумевают некие способы адресации, т.е. нужно знать как эти алгоритмы переносить на C#, и понимать, что у нас есть свобода выбора: разместить объект в куче, например, или без проблем пользовать value-type, но передать его в аналогичную точку алгоритма по ссылке.
S>За ссылку спасибо, но это ничего не доказывает в обсуждаемом предмете.
Там расписана семантика l-value, которая в точности совпадает с семантикой ссылок. Вернись, насчет чего я там дал этот линк.
Например, здесь ссылки нет, а ссылочная семантика есть (вторая строка):
int i = 0;
i = 42;
V>>Есть такой прием, называется — "оборачивание ссылок". Этот прием пользуется тем, что под ссылку-мембер всегда выделяют память, поэтому можно сделать структуру с одним полем — ссылкой, и оперировать этой структурой как обычным значением. S>Косвенно и не для каждой ссылки
Для каждой. Важно, что я могу через этот прием безболезненно использовать такую завернутую ссылку там, где ранее использовал указатель, полностью повторив даже "побочную" семантику, в т.ч. взятия адреса этого объекта и мутации его значения.
S>То что ссылка есть синтаксический сахар над константным указателем — возражать не будут. Но это не заставляет меня думать о ссылке как о переменной.
А если она идет как параметр метода, то что это? Разве аргумент метода не является автоматически локальной переменной?
Да и это не принципиально. Важно, что мы можем создавать копии ссылок, вместо копий целевых объектов, и нам для создания таких копий не требуется знать внутреннее устройство ссылок. Отсюда потребность знать устройство ссылки близится к 0-лю. Для сравнени, я даже не припомню, чтобы хоть раз оперировать указателем именно как числовым значением, кроме случая отладочной информации, но! для ссылок в дебагере я могу получить ту же информацию, что и для указателей... оп-па.
В общем, тут высказался на этот счет, почему таки ссылки и указатели обеспечивают равную требуемую семантику (а ничего другого мне, программисту, и не надо): http://www.rsdn.ru/forum/philosophy/4516835.aspx
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Я не знаю VB и VB.NET, но знаю что передача по ссылке в дотнете никак не связана с COM.
V>Таки связана. Где требуется COM interop и по сигнатуре идет указатель на структуру, там ты можешь передать ссылочный тип, либо же value-тип, но через модификатор ref, чтобы получить такой же уровень индирекции.
т.е. связана тем что ref и по ссылке можно передавать значения в COM? Ну так-то да, связана
S>>Я уже припух объяснять, что значение переменной типа указателя — есть указатель и он хранится в памяти, отведенной для переменной. Значение "переменной" типа ссылка хранится в другом месте, чем хранится внутреннее представление ссылки. При этом, нет возможности (легальной) взять адрес внутреннего представления ссылки и как-то повлиять на его содержимое.
V>Ну... Это пошла сугубо философия, не имеющая отношение к реально происходящему, в дебри которой я лезть всё равно не стану. Из того факта, что ты не можешь узнать устройство ссылки, ты делаешь слишком далекоидущие выводы.
Мне так не кажется V>Меня, как программиста, вообще не должно интересовать ничего, кроме уровня косвенности в каждом конкретном случае, потому что косвенное обращение само по себе и есть основа гибкости и повторного использования одного и того же кода для разных экземпляров объектов/значений. И в этом плане, как управляемые ссылки дотнета (т.е. аналоги указателей С/С++), так и ссылки на мемберы или члены стека (т.е. аналоги ссылок в С++) демонстрируют одни и те же характеристики для программиста... Особенно, если не стоит задача узнать устройство ссылки... Важно лишь это — создание копии ссылки не есть создание копии целевого объекта/значения, и как следствие: несколько ссылок может ссылаться на один объект/значение, или же один и тот же аргумент-ссылка может ссылаться на разные объекты/значения в разных вызовах. А остальное непринципиально.
Тот же уровень косвенности ничего не говорит о том, где переменная, а где нет.
V>В общем, я такими вещами не заморачиваюсь и могу, разве что, опять отослать к способам адресации. Только так можно не заблудиться в "Философии". Потому как алгоритмы (просто алгоритмы, без привязки к языку) именно подразумевают некие способы адресации, т.е. нужно знать как эти алгоритмы переносить на C#, и понимать, что у нас есть свобода выбора: разместить объект в куче, например, или без проблем пользовать value-type, но передать его в аналогичную точку алгоритма по ссылке.
Со своим пониманием где есть переменная, а где нет, я как-то не испытываю проблем с переносом алгоритмов на С# и не только.
S>>За ссылку спасибо, но это ничего не доказывает в обсуждаемом предмете.
V>Там расписана семантика l-value, которая в точности совпадает с семантикой ссылок. Вернись, насчет чего я там дал этот линк. V>Например, здесь ссылки нет, а ссылочная семантика есть (вторая строка): V>
V>int i = 0;
V>i = 42;
V>
Хорошо. Но здесь переменная есть и в точности одна, а ссылки нет, хоть и ссылочная семантика есть.
V>>>Есть такой прием, называется — "оборачивание ссылок". Этот прием пользуется тем, что под ссылку-мембер всегда выделяют память, поэтому можно сделать структуру с одним полем — ссылкой, и оперировать этой структурой как обычным значением. S>>Косвенно и не для каждой ссылки
V>Для каждой. Важно, что я могу через этот прием безболезненно использовать такую завернутую ссылку там, где ранее использовал указатель, полностью повторив даже "побочную" семантику, в т.ч. взятия адреса этого объекта и мутации его значения.
int i = 0;
int &i1 = i;
Покажи как взять адрес служебной информации для ссылки i1 с помощью оборачивания
S>>То что ссылка есть синтаксический сахар над константным указателем — возражать не будут. Но это не заставляет меня думать о ссылке как о переменной.
V>А если она идет как параметр метода, то что это? Разве аргумент метода не является автоматически локальной переменной?
Предпочитаю считать что переменная остается за бортом метода. V>Да и это не принципиально. Важно, что мы можем создавать копии ссылок, вместо копий целевых объектов, и нам для создания таких копий не требуется знать внутреннее устройство ссылок. Отсюда потребность знать устройство ссылки близится к 0-лю. Для сравнени, я даже не припомню, чтобы хоть раз оперировать указателем именно как числовым значением, кроме случая отладочной информации, но! для ссылок в дебагере я могу получить ту же информацию, что и для указателей... оп-па.
V>В общем, тут высказался на этот счет, почему таки ссылки и указатели обеспечивают равную требуемую семантику (а ничего другого мне, программисту, и не надо): http://www.rsdn.ru/forum/philosophy/4516835.aspx
V>>Таки связана. Где требуется COM interop и по сигнатуре идет указатель на структуру, там ты можешь передать ссылочный тип, либо же value-тип, но через модификатор ref, чтобы получить такой же уровень индирекции. S>т.е. связана тем что ref и по ссылке можно передавать значения в COM? Ну так-то да, связана
Не просто можно, а есть четкое соответствие, что в VB, что в VB.Net. Кстати, для стековых value-type даже маршаллинг не выполняется, прямо ссылка на них подается туда, где в COM ожидается указатель.
V>>В общем, я такими вещами не заморачиваюсь и могу, разве что, опять отослать к способам адресации. Только так можно не заблудиться в "Философии". Потому как алгоритмы (просто алгоритмы, без привязки к языку) именно подразумевают некие способы адресации, т.е. нужно знать как эти алгоритмы переносить на C#, и понимать, что у нас есть свобода выбора: разместить объект в куче, например, или без проблем пользовать value-type, но передать его в аналогичную точку алгоритма по ссылке. S>Со своим пониманием где есть переменная, а где нет, я как-то не испытываю проблем с переносом алгоритмов на С# и не только.
Ключевое было — взаимозаменяемость использования ссылочных типов, либо value-type для реализации алгоритмов.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Таки связана. Где требуется COM interop и по сигнатуре идет указатель на структуру, там ты можешь передать ссылочный тип, либо же value-тип, но через модификатор ref, чтобы получить такой же уровень индирекции. S>>т.е. связана тем что ref и по ссылке можно передавать значения в COM? Ну так-то да, связана
V>Не просто можно, а есть четкое соответствие, что в VB, что в VB.Net. Кстати, для стековых value-type даже маршаллинг не выполняется, прямо ссылка на них подается туда, где в COM ожидается указатель.
Дык это характерно вообще для интеропа, а COM — это лишь частный случай.
V>>>В общем, я такими вещами не заморачиваюсь и могу, разве что, опять отослать к способам адресации. Только так можно не заблудиться в "Философии". Потому как алгоритмы (просто алгоритмы, без привязки к языку) именно подразумевают некие способы адресации, т.е. нужно знать как эти алгоритмы переносить на C#, и понимать, что у нас есть свобода выбора: разместить объект в куче, например, или без проблем пользовать value-type, но передать его в аналогичную точку алгоритма по ссылке. S>>Со своим пониманием где есть переменная, а где нет, я как-то не испытываю проблем с переносом алгоритмов на С# и не только.
V>Ключевое было — взаимозаменяемость использования ссылочных типов, либо value-type для реализации алгоритмов.
Взаимозаменяемости нет. Как только value передается по ссылке, говорить о передаче value неуместно.
Здравствуйте, samius, Вы писали:
V>>Не просто можно, а есть четкое соответствие, что в VB, что в VB.Net. Кстати, для стековых value-type даже маршаллинг не выполняется, прямо ссылка на них подается туда, где в COM ожидается указатель. S>Дык это характерно вообще для интеропа, а COM — это лишь частный случай.
Ну коль ты упомянул термин ByRef, то его ноги растут из VB, у которого объекты являются объектами COM, и я тебе напомнил про маппинг ByRef на указатели в COM. А так-то да, на дотнетный p-invoke это тоже распространяется.
S>>>Со своим пониманием где есть переменная, а где нет, я как-то не испытываю проблем с переносом алгоритмов на С# и не только.
V>>Ключевое было — взаимозаменяемость использования ссылочных типов, либо value-type для реализации алгоритмов. S>Взаимозаменяемости нет. Как только value передается по ссылке, говорить о передаче value неуместно.
Таки есть. Если алгоритм требует некий экземпляр объекта для мутирующих действий, то можно пользовать как ссылочный тип, так и value-тип, передаваемый по ref. Два этих способа взаимозаменямы, и позволяют рефакторить код в целях оптимизации. В С++ аналогично, сценарии доступа по ссылке и по указателю взаимозамеяемы. Иногда я типы аргументов методов в С++ меняю с указателя на ссылки или в обратном направлении. С какого перепугу они при этом должны перестать становиться переменными, или опять начинать ими быть — ты все-равно не объяснишь, это противоречит здравому смыслу.
Здравствуйте, samius, Вы писали:
V>>Я ссылался на определение, что переменная — это именованная область памяти, что есть тоже самое, что и алиас/синоним некоего представления (пусть числового) адреса этой области. Я просто обратил внимание, что имя-то в процессе компиляции/линковки уйдет, а область памяти — нет, будь оно хоть чем: глобальной областью, локальной или полем другого объекта. S>Я не настаиваю на точности определения, но раз оно говорит что переменная — это именованная область памяти, а имени в рантайме нет, то значит согласно этому определению, в рантайме нет переменной.
Если область памяти никуда не делась, то позволю себе думать, что переменная есть. И убедиться в этом легко, положив рядом с программой PDB-файл. А вот если в процессе компиляции переменная "ушла" стараниями оптимизатора, т.е. "ушла" некая область памяти, то только в этом случае переменной не будет в рантайм, в чем опять же можно убедиться, положив рядом тот же PDB: в этом случае исходному символическому имени не будет соответствовать никакая область памяти скомпилированной программы.
========
Да и вообще... Мы же в программе не над символьными именами действия совершаем, а именно над ячейками памяти, над переменными, конкретные экземпляры которых указываем через символьные алиасы.
Здравствуйте, samius, Вы писали:
V>>Там расписана семантика l-value, которая в точности совпадает с семантикой ссылок. Вернись, насчет чего я там дал этот линк. V>>Например, здесь ссылки нет, а ссылочная семантика есть (вторая строка): V>>
V>>int i = 0;
V>>i = 42;
V>>
S>Хорошо. Но здесь переменная есть и в точности одна, а ссылки нет, хоть и ссылочная семантика есть.
А что не так-то? l-value в примере является временным значением. А временное значение не является переменной, хотя может, в свою очередь, иметь любой тип. Т.е. тебя же не смущает, когда мы имеем временное значение типа-указателя? Т.е. переменной нет, а указатель таки есть. Почему для ссылки это не так?
static int i = 0;
static int & ref2i() { return i; }
static int * ptr2i() { return &i; }
ref2i() = 42;
*ptr2i() = 42;
В этом примере одна переменная, а для доступа к ней используется ссылка и указатель, хотя ни одна, ни другой не являются переменными, но являются временными значениями, возвращаемыми ф-ями. Я ведь привык думать, что если ф-ия не void, то она возвращает некоторое значение. Поэтому для меняя ссылка — это такое же обычное значение ссылочного типа.
В этом примере самая важная строка — последняя. Об эту строку спотыкаются многие начинающие С/С++ программисты. Разыменование указателя — это не есть непосредственная операция извлечения значения, т.е. в данном случае не есть извлечение значения типа int и формирование временного значения, куда мы потом будем пытаться присвоить 42. Разыменование указателя — это просто приведение типа выражения, а коль выражение используется как l-value, то здесь приведение указателя к ссылке. По факту, коль уровень косвенности у обоих выражений одинаков, они рожают одинаковый бинарный код.
V>>Для каждой. Важно, что я могу через этот прием безболезненно использовать такую завернутую ссылку там, где ранее использовал указатель, полностью повторив даже "побочную" семантику, в т.ч. взятия адреса этого объекта и мутации его значения. S>
S>int i = 0;
S>int &i1 = i;
S>
S>Покажи как взять адрес служебной информации для ссылки i1 с помощью оборачивания
Для этого ее надо разместить полем некоей структуры и оперировать этой структурой вместо ссылки:
int i = 0;
struct RefBox { int & ref; } iref = { i };
Для семантики мутирования надо вручную определить оператор присвоения и конструктор копирования. После этого можно пользовать структуру целиком в тех местах, где пользовался int*, с сохранением семантики взятия адреса и т.д. Осталось еще определить для этой структуры такой метод:
int * operator->() { return &ref; }
и можно будет пользовать вместо указателя даже без всякого рефакторинга, развязавшись только через typedef.
V>>А если она идет как параметр метода, то что это? Разве аргумент метода не является автоматически локальной переменной? S>Предпочитаю считать что переменная остается за бортом метода.
А в стеке что лежит при использовании соглашений вызова cdecl или pascal?
V>>Да и это не принципиально. Важно, что мы можем создавать копии ссылок, вместо копий целевых объектов, и нам для создания таких копий не требуется знать внутреннее устройство ссылок. Отсюда потребность знать устройство ссылки близится к 0-лю. Для сравнени, я даже не припомню, чтобы хоть раз оперировать указателем именно как числовым значением, кроме случая отладочной информации, но! для ссылок в дебагере я могу получить ту же информацию, что и для указателей... оп-па.
V>>В общем, тут высказался на этот счет, почему таки ссылки и указатели обеспечивают равную требуемую семантику (а ничего другого мне, программисту, и не надо): http://www.rsdn.ru/forum/philosophy/4516835.aspx
S>Ну так раз не надо, то позволь мне и дальше считать что ссылка и переменная — разные вещи.
Да позволю, разумеется, но не упустил ли ты выделенное? Я могу копировать/размножать ссылки. Делать их оч. много, даже занять ими всю доступную память. Никакого разрыва шаблона не происходит?
===========
ИМХО, рядом в ветке у нас идут разногласия насчет того, что есть переменная. Я пока не смог понять, что ты понимаешь под этим термином, похоже некую абстракцию, суть которой от меня всё еще ускользает. Вполне возможно, что именно тип ссылки каким-то образом запрещает переменной быть именно переменной в твоем понимании. Хотя, в начале поста я показал, что тип данных и переменная — не одно и то же, но коль есть некий тип, всегда можно создать переменную этого типа, даже в дотнете, начиная с 4-й версии .
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Не просто можно, а есть четкое соответствие, что в VB, что в VB.Net. Кстати, для стековых value-type даже маршаллинг не выполняется, прямо ссылка на них подается туда, где в COM ожидается указатель. S>>Дык это характерно вообще для интеропа, а COM — это лишь частный случай.
V>Ну коль ты упомянул термин ByRef, то его ноги растут из VB, у которого объекты являются объектами COM, и я тебе напомнил про маппинг ByRef на указатели в COM. А так-то да, на дотнетный p-invoke это тоже распространяется.
Ноги термина-то может и растут, но сам ref к COM имеет лишь то отношение, что можно из safe C# подавать в методы структуры по ссылке. Ну и что интероп может взять реф ссылки и положить туда обертку над COM объектом, вернувшимся из метода через аут параметр.
V>>>Ключевое было — взаимозаменяемость использования ссылочных типов, либо value-type для реализации алгоритмов. S>>Взаимозаменяемости нет. Как только value передается по ссылке, говорить о передаче value неуместно.
V>Таки есть. Если алгоритм требует некий экземпляр объекта для мутирующих действий, то можно пользовать как ссылочный тип, так и value-тип, передаваемый по ref. Два этих способа взаимозаменямы, и позволяют рефакторить код в целях оптимизации.
Это не два разных способа, это один способ. value по ref — это ссылочный таки тип по спецификации. Я ошибся, когда утверждал что ссылочный тип это нечто другое. V>В С++ аналогично, сценарии доступа по ссылке и по указателю взаимозамеяемы. Иногда я типы аргументов методов в С++ меняю с указателя на ссылки или в обратном направлении. С какого перепугу они при этом должны перестать становиться переменными, или опять начинать ими быть — ты все-равно не объяснишь, это противоречит здравому смыслу.
Я пытался, но ты смотришь не на язык, а на стек, в то время как переменная — понятие языка а не стека и реализации.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Я не настаиваю на точности определения, но раз оно говорит что переменная — это именованная область памяти, а имени в рантайме нет, то значит согласно этому определению, в рантайме нет переменной.
V>Если область памяти никуда не делась, то позволю себе думать, что переменная есть. И убедиться в этом легко, положив рядом с программой PDB-файл. А вот если в процессе компиляции переменная "ушла" стараниями оптимизатора, т.е. "ушла" некая область памяти, то только в этом случае переменной не будет в рантайм, в чем опять же можно убедиться, положив рядом тот же PDB: в этом случае исходному символическому имени не будет соответствовать никакая область памяти скомпилированной программы.
V>======== V>Да и вообще... Мы же в программе не над символьными именами действия совершаем, а именно над ячейками памяти, над переменными, конкретные экземпляры которых указываем через символьные алиасы.
Мы в программе совершаем действия над переменными. Но в рантайме у нас ячейки памяти. И PDB тут непричем. Он лишь соответствие (как ты и сказал) между ячейкой в рантайме и именем переменной в программе.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали: V>>>Например, здесь ссылки нет, а ссылочная семантика есть (вторая строка): V>>>
V>>>int i = 0;
V>>>i = 42;
V>>>
S>>Хорошо. Но здесь переменная есть и в точности одна, а ссылки нет, хоть и ссылочная семантика есть.
V>А что не так-то? l-value в примере является временным значением. А временное значение не является переменной, хотя может, в свою очередь, иметь любой тип. Т.е. тебя же не смущает, когда мы имеем временное значение типа-указателя? Т.е. переменной нет, а указатель таки есть. Почему для ссылки это не так?
Что-то я не понял. Какое еще временное значение? Здесь в качестве l-value выступает переменная i. Откуда указатели? Ты о примере выше, или который ниже?
V>
V>static int i = 0;
V>static int & ref2i() { return i; }
V>static int * ptr2i() { return &i; }
V>ref2i() = 42;
V>*ptr2i() = 42;
V>
V>В этом примере одна переменная, а для доступа к ней используется ссылка и указатель, хотя ни одна, ни другой не являются переменными, но являются временными значениями, возвращаемыми ф-ями. Я ведь привык думать, что если ф-ия не void, то она возвращает некоторое значение. Поэтому для меняя ссылка — это такое же обычное значение ссылочного типа.
Тут все верно. Переменная одна, и два временных значения. Одно временное значение ссылка, другое адрес. Хотя на стеке это может быть одним и тем же.
V>В этом примере самая важная строка — последняя. Об эту строку спотыкаются многие начинающие С/С++ программисты. Разыменование указателя — это не есть непосредственная операция извлечения значения, т.е. в данном случае не есть извлечение значения типа int и формирование временного значения, куда мы потом будем пытаться присвоить 42.
Да ладно? Я дал повод считать что я полагаю о том что разыменование извлекает значение? В таком случае бы следующий код не изменял бы значение i:
*&i = 42;
А я уже слишком давно знаком с C++ что бы не знать, что он делает. 20 лет в обед. V>Разыменование указателя — это просто приведение типа выражения, а коль выражение используется как l-value, то здесь приведение указателя к ссылке. По факту, коль уровень косвенности у обоих выражений одинаков, они рожают одинаковый бинарный код.
Разыменование это НЕ приведение типа выражения. Это переход от адреса к адресуемому месту в памяти.
А одинаковый бинарный код это не повод делать какие-то выводы в отношении используемых сущностей уровня языка.
S>>
S>>int i = 0;
S>>int &i1 = i;
S>>
S>>Покажи как взять адрес служебной информации для ссылки i1 с помощью оборачивания
V>Для этого ее надо разместить полем некоей структуры и оперировать этой структурой вместо ссылки: V>int i = 0; V>struct RefBox { int & ref; } iref = { i };
ты возьмешь адрес другой ссылки. Пусть служебная информация там будет та же, но ссылка-то другая. V>Для семантики мутирования надо вручную определить оператор присвоения и конструктор копирования. После этого можно пользовать структуру целиком в тех местах, где пользовался int*, с сохранением семантики взятия адреса и т.д. Осталось еще определить для этой структуры такой метод: V>int * operator->() { return &ref; } V>и можно будет пользовать вместо указателя даже без всякого рефакторинга, развязавшись только через typedef.
Это ничего не даст в споре о том, является ли ссылка переменной.
V>>>А если она идет как параметр метода, то что это? Разве аргумент метода не является автоматически локальной переменной? S>>Предпочитаю считать что переменная остается за бортом метода.
V>А в стеке что лежит при использовании соглашений вызова cdecl или pascal?
Ну вот, опять стек. В стеке будет лежать адрес.
V>>>Да и это не принципиально. Важно, что мы можем создавать копии ссылок, вместо копий целевых объектов, и нам для создания таких копий не требуется знать внутреннее устройство ссылок.
V>Да позволю, разумеется, но не упустил ли ты выделенное? Я могу копировать/размножать ссылки. Делать их оч. много, даже занять ими всю доступную память. Никакого разрыва шаблона не происходит?
Нет, не происходит. Я могу занять память чем угодно, это не будет означать что она занята переменными.
V>=========== V>ИМХО, рядом в ветке у нас идут разногласия насчет того, что есть переменная. Я пока не смог понять, что ты понимаешь под этим термином, похоже некую абстракцию, суть которой от меня всё еще ускользает. Вполне возможно, что именно тип ссылки каким-то образом запрещает переменной быть именно переменной в твоем понимании.
Я уже писал что ссылка представляет собой алиас того, на что она ссылается, в то время как указатель — это адрес, которым можно оперировать. Оперировать ссылкой нельзя, т.к. вместо нее операции будут происходить над местом, на которое ссылается ссылка.
V>Хотя, в начале поста я показал, что тип данных и переменная — не одно и то же, но коль есть некий тип, всегда можно создать переменную этого типа, даже в дотнете, начиная с 4-й версии .
Вот что интересно, будет ли корректной инструкция ldloc для "переменной" такого типа. Что будет являться ее результатом?
Здравствуйте, samius, Вы писали:
V>>А что не так-то? l-value в примере является временным значением. А временное значение не является переменной, хотя может, в свою очередь, иметь любой тип. Т.е. тебя же не смущает, когда мы имеем временное значение типа-указателя? Т.е. переменной нет, а указатель таки есть. Почему для ссылки это не так? S>Что-то я не понял. Какое еще временное значение? Здесь в качестве l-value выступает переменная i. Откуда указатели? Ты о примере выше, или который ниже?
Да о всё о том же, что l-value это не само значение, а классическая ссылка на него.
S>Тут все верно. Переменная одна, и два временных значения. Одно временное значение ссылка, другое адрес. Хотя на стеке это может быть одним и тем же.
Ну вот, ты уже согласился с тем, что ссылка — это тоже значение. ЧТД. Осталось ответить на вопрос, почему я могу иметь значение некоторого типа, а переменную этого типа создать не могу?
S>Разыменование это НЕ приведение типа выражения. Это переход от адреса к адресуемому месту в памяти.
Хм, ну это опять же вопрос сугубо точки зрения. При преобразовании типов в С++ в общем случае что-то происходит, вплоть до порождения новых объектов.
Разыменование — это добавление уровня индирекции, конечно тип меняется.
S>А одинаковый бинарный код это не повод делать какие-то выводы в отношении используемых сущностей уровня языка.
Ну коль язык это инструмент, то мне таки надо знать, что же этот инструмент делает.
V>>Для этого ее надо разместить полем некоей структуры и оперировать этой структурой вместо ссылки: V>>int i = 0; V>>struct RefBox { int & ref; } iref = { i }; S>ты возьмешь адрес другой ссылки. Пусть служебная информация там будет та же, но ссылка-то другая.
Да это не принципиально. Этот прием даже в бусте пользуют, когда надо хранить/копировать/передавать именно ссылку, а не указуемое значение. Главное здесь что — мы оперируем ссылкой, ссылающейся на всё тот же целевой объект, т.е. сохраняем единственно требуемую от ссылки семантику. Остальное никого не интересует.
S>Это ничего не даст в споре о том, является ли ссылка переменной.
Разве? С каких пор поле объекта перестало быть разновидностью переменной?
V>>>>А если она идет как параметр метода, то что это? Разве аргумент метода не является автоматически локальной переменной? S>>>Предпочитаю считать что переменная остается за бортом метода.
V>>А в стеке что лежит при использовании соглашений вызова cdecl или pascal? S>Ну вот, опять стек. В стеке будет лежать адрес.
В стеке будет лежать значение определенного типа, только это и важно. Я кажется начал догонять твой взгляд на вещи... да, в случае ссылки мы оперируем значением, которое расположено "где-то". Как и в случае указателей. Но это не есть ссылка именно на переменную. Ведь запросто можно сохранить ссылку на значение в куче, на которое больше никто не указывает, т.е. ни о какой другой переменной, кроме как об единственно ссылающейся это ссылке, речи быть не может. Поэтому даже с т.з. твоей логики, за бортом остается не переменная, а именно значение. Согласен? Ну а мой поинт лишь в том, что локальная переменная ссылочного типа на это значение ссылается.
V>>Да позволю, разумеется, но не упустил ли ты выделенное? Я могу копировать/размножать ссылки. Делать их оч. много, даже занять ими всю доступную память. Никакого разрыва шаблона не происходит? S>Нет, не происходит. Я могу занять память чем угодно, это не будет означать что она занята переменными.
Это если мы эту память потеряли насовсем, то да. А если связали в граф, то занята она таки самыми что ни на есть живыми переменными.
S>Я уже писал что ссылка представляет собой алиас того, на что она ссылается, в то время как указатель — это адрес, которым можно оперировать.
Ну и как можно оперировать константным адресом, с которым я сравнил ссылку? Распечатать его числовое представление для целей отладки?
V>>Хотя, в начале поста я показал, что тип данных и переменная — не одно и то же, но коль есть некий тип, всегда можно создать переменную этого типа, даже в дотнете, начиная с 4-й версии . S>Вот что интересно, будет ли корректной инструкция ldloc для "переменной" такого типа. Что будет являться ее результатом?
ldloc грузит само значение в стек, результатом будет копия значения ссылки на стеке.
Гораздо интереснее взять ldloca.
Здравствуйте, samius, Вы писали:
S>Я пытался, но ты смотришь не на язык, а на стек, в то время как переменная — понятие языка а не стека и реализации.
Э нет, переменная — это "инструкция" высокоуровневого ЯП. Программу мы пишем не для времени компиляции, а именно для рантайма. И переменная — это инструкция управления/распределения памяти, где само фактическое распределение выполняется опираясь на типы значений, которые необходимо разместить в некоей памяти. И не надо пытаться строить такую невинность, что это всё далекие абстракции, которыми мы оперируем и не интересуемся реально происходящим. Дудки. Ты именно всегда непосредственно указываешь для переменной область памяти, в которой ее необходимо распределить: будь то глобальная область памяти, локальная или в области памяти, занимаемой объектом (т.е. в виде поля другого типа). Абтрагирование от конкретики происходит только на уровне типов, т.е. мы абстрагируемся лишь от размеров памяти, требуемых для значений (и как побочный эффект — защищаемся от неверной интерпретации этой памяти), больше ни от чего. Остальное мы указываем очень даже конкретно из расчета как нам конкретно надо, чтобы оно работало в рантайм.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>А что не так-то? l-value в примере является временным значением. А временное значение не является переменной, хотя может, в свою очередь, иметь любой тип. Т.е. тебя же не смущает, когда мы имеем временное значение типа-указателя? Т.е. переменной нет, а указатель таки есть. Почему для ссылки это не так? S>>Что-то я не понял. Какое еще временное значение? Здесь в качестве l-value выступает переменная i. Откуда указатели? Ты о примере выше, или который ниже?
V>Да о всё о том же, что l-value это не само значение, а классическая ссылка на него.
l-value это все-таки место, а не ссылка. Сам же говорил, что в C нет ссылок
S>>Тут все верно. Переменная одна, и два временных значения. Одно временное значение ссылка, другое адрес. Хотя на стеке это может быть одним и тем же.
V>Ну вот, ты уже согласился с тем, что ссылка — это тоже значение. ЧТД. Осталось ответить на вопрос, почему я могу иметь значение некоторого типа, а переменную этого типа создать не могу?
Давай все-таки разграничивать о каких значениях мы говорим. Формально значением ссылки является то, на что она ссылается. Ты же говоришь о неком значении, которое является служебной информацией ссылки. Да, ты можешь создать переменную, которая будет содержать служебную информацию ссылки. Но значением ссылки будет не эта информация, а та, на которую она ссылается посредством этой служебной информации.
S>>Разыменование это НЕ приведение типа выражения. Это переход от адреса к адресуемому месту в памяти.
V>Хм, ну это опять же вопрос сугубо точки зрения. При преобразовании типов в С++ в общем случае что-то происходит, вплоть до порождения новых объектов.
А при разыменовании ничего не происходит. V>Разыменование — это добавление уровня индирекции, конечно тип меняется.
Тип меняется, но называть разыменование приведением типа — это лихо.
S>>А одинаковый бинарный код это не повод делать какие-то выводы в отношении используемых сущностей уровня языка.
V>Ну коль язык это инструмент, то мне таки надо знать, что же этот инструмент делает.
А делать инструмент может нечто значительно отличающееся от языковых терминов. Ты можешь находить некоторые соответствия, но делать по ним выводы о сущностях уровня языка в общем случае неверно.
S>>ты возьмешь адрес другой ссылки. Пусть служебная информация там будет та же, но ссылка-то другая.
V>Да это не принципиально. Этот прием даже в бусте пользуют, когда надо хранить/копировать/передавать именно ссылку, а не указуемое значение. Главное здесь что — мы оперируем ссылкой, ссылающейся на всё тот же целевой объект, т.е. сохраняем единственно требуемую от ссылки семантику. Остальное никого не интересует.
Мы не оперируем ссылкой, мы создаем новую ссылку каждый раз.
S>>Это ничего не даст в споре о том, является ли ссылка переменной.
V>Разве? С каких пор поле объекта перестало быть разновидностью переменной?
с тех пор, когда поле объекта стало ссылкой.
S>>Ну вот, опять стек. В стеке будет лежать адрес.
V>В стеке будет лежать значение определенного типа, только это и важно. Я кажется начал догонять твой взгляд на вещи... да, в случае ссылки мы оперируем значением, которое расположено "где-то". Как и в случае указателей. Но это не есть ссылка именно на переменную. Ведь запросто можно сохранить ссылку на значение в куче, на которое больше никто не указывает, т.е. ни о какой другой переменной, кроме как об единственно ссылающейся это ссылке, речи быть не может. Поэтому даже с т.з. твоей логики, за бортом остается не переменная, а именно значение. Согласен? Ну а мой поинт лишь в том, что локальная переменная ссылочного типа на это значение ссылается.
Я уже писал, что ссылка ссылается на место. Это место может быть переменной. А может быть местом в куче.
V>>>Да позволю, разумеется, но не упустил ли ты выделенное? Я могу копировать/размножать ссылки. Делать их оч. много, даже занять ими всю доступную память. Никакого разрыва шаблона не происходит? S>>Нет, не происходит. Я могу занять память чем угодно, это не будет означать что она занята переменными.
V>Это если мы эту память потеряли насовсем, то да. А если связали в граф, то занята она таки самыми что ни на есть живыми переменными.
Ты опять применяешь термин языка к рантайму. Представь что мы где-то в дебрях рекурсии без хвостовой оптимизации (пусть факториала). Стек кончился. Чем память забита? Да хрен, знает, а живая переменная лишь одна!
S>>Я уже писал что ссылка представляет собой алиас того, на что она ссылается, в то время как указатель — это адрес, которым можно оперировать.
V>Ну и как можно оперировать константным адресом, с которым я сравнил ссылку? Распечатать его числовое представление для целей отладки?
И это тоже. А еще можем взять адрес адреса и куда-нибудь передать.
V>>>Хотя, в начале поста я показал, что тип данных и переменная — не одно и то же, но коль есть некий тип, всегда можно создать переменную этого типа, даже в дотнете, начиная с 4-й версии . S>>Вот что интересно, будет ли корректной инструкция ldloc для "переменной" такого типа. Что будет являться ее результатом?
V>ldloc грузит само значение в стек, результатом будет копия значения ссылки на стеке.
Значение ссылки — это то место, на которое она ссылается. V>Гораздо интереснее взять ldloca.
Здравствуйте, samius, Вы писали:
V>>>>А что не так-то? l-value в примере является временным значением. А временное значение не является переменной, хотя может, в свою очередь, иметь любой тип. Т.е. тебя же не смущает, когда мы имеем временное значение типа-указателя? Т.е. переменной нет, а указатель таки есть. Почему для ссылки это не так? S>>>Что-то я не понял. Какое еще временное значение? Здесь в качестве l-value выступает переменная i. Откуда указатели? Ты о примере выше, или который ниже?
V>>Да о всё о том же, что l-value это не само значение, а классическая ссылка на него. S>l-value это все-таки место, а не ссылка. Сам же говорил, что в C нет ссылок
Ну так "место" — это и есть отсылка к значению, а не само значение.
Да, говорил, насчет С, что ссылок нет, а ссылочная семантика есть.
Помнишь, что l-value бывает не только во время присвоения по известному адресу, т.е. при присвоении значения переменной, но и вычисляемое? Поэтому не так всё просто с "местом".
V>>Ну вот, ты уже согласился с тем, что ссылка — это тоже значение. ЧТД. Осталось ответить на вопрос, почему я могу иметь значение некоторого типа, а переменную этого типа создать не могу? S>Давай все-таки разграничивать о каких значениях мы говорим. Формально значением ссылки является то, на что она ссылается. Ты же говоришь о неком значении, которое является служебной информацией ссылки. Да, ты можешь создать переменную, которая будет содержать служебную информацию ссылки. Но значением ссылки будет не эта информация, а та, на которую она ссылается посредством этой служебной информации.
Это будет "значением по ссылке", именно так его принято называть.
V>>Ну коль язык это инструмент, то мне таки надо знать, что же этот инструмент делает. S>А делать инструмент может нечто значительно отличающееся от языковых терминов. Ты можешь находить некоторые соответствия, но делать по ним выводы о сущностях уровня языка в общем случае неверно.
Не может, иначе инструмент станет негоден. Он должен что-то делать согласно спецификации. Причем, сама спецификация, в свою очередь, построена на основе общепринятой терминологии, а не какой-то специальной-абстрактной.
V>>Да это не принципиально. Этот прием даже в бусте пользуют, когда надо хранить/копировать/передавать именно ссылку, а не указуемое значение. Главное здесь что — мы оперируем ссылкой, ссылающейся на всё тот же целевой объект, т.е. сохраняем единственно требуемую от ссылки семантику. Остальное никого не интересует. S>Мы не оперируем ссылкой, мы создаем новую ссылку каждый раз.
Именно, только это от ссылки и требуется — при копировании их, не копировать целевое значение. Больше никакой семантической нагрузки они не несут.
V>>Разве? С каких пор поле объекта перестало быть разновидностью переменной? S>с тех пор, когда поле объекта стало ссылкой.
А что в этом случае страшное произошло? Память не из адреса объекта под ссылочную переменную выделилась или что-то еще?
S>Я уже писал, что ссылка ссылается на место. Это место может быть переменной. А может быть местом в куче.
Это ты первый раз в этом посте написал, до этого настаивал исключительно на переменной.
Так по-немногу и доберемся до цели.
V>>Это если мы эту память потеряли насовсем, то да. А если связали в граф, то занята она таки самыми что ни на есть живыми переменными. S>Ты опять применяешь термин языка к рантайму. Представь что мы где-то в дебрях рекурсии без хвостовой оптимизации (пусть факториала). Стек кончился. Чем память забита? Да хрен, знает, а живая переменная лишь одна!
Если в стеке нет временных переменных, а только адреса возвратов, то сложно не переделать в хвостовую рекурсию... А если там параметры — то они суть классические локальные переменные. "Язык рантайма" тут не при чем.
V>>Ну и как можно оперировать константным адресом, с которым я сравнил ссылку? Распечатать его числовое представление для целей отладки? S>И это тоже. А еще можем взять адрес адреса и куда-нибудь передать.
Внимание, вопрос! Зачем это надо для адреса, который константа? (с которым сравнили ссылку)
Серьезно, аж интересно стало.
V>>ldloc грузит само значение в стек, результатом будет копия значения ссылки на стеке. S>Значение ссылки — это то место, на которое она ссылается.
Это на ЯВУ, а в опкодах CLI — это адрес. После прочтения значения ссылки надо делать ldobj (или как там его)...
S>>>Я пытался, но ты смотришь не на язык, а на стек, в то время как переменная — понятие языка а не стека и реализации.
V>>Э нет, переменная — это "инструкция" высокоуровневого ЯП. Программу мы пишем не для времени компиляции, а именно для рантайма. И переменная — это инструкция управления/распределения памяти, где само фактическое распределение выполняется опираясь на типы значений, которые необходимо разместить в некоей памяти. И не надо пытаться строить такую невинность, что это всё далекие абстракции, которыми мы оперируем и не интересуемся реально происходящим. Дудки. Ты именно всегда непосредственно указываешь для переменной область памяти, в которой ее необходимо распределить: будь то глобальная область памяти, локальная или в области памяти, занимаемой объектом (т.е. в виде поля другого типа). Абтрагирование от конкретики происходит только на уровне типов, т.е. мы абстрагируемся лишь от размеров памяти, требуемых для значений (и как побочный эффект — защищаемся от неверной интерпретации этой памяти), больше ни от чего. Остальное мы указываем очень даже конкретно из расчета как нам конкретно надо, чтобы оно работало в рантайм. S>А тебя не смущает, что в рантайме может не оказаться того, что ты так старательно и конкретно указывал?
Ты имеешь ввиду суперкомпиляцию? Нет, не смущает. У меня на уровне ЯП есть некий инструментарий при работе с памятью: куча, стек, поля составных типов, глобальные (статические) переменные, где-то еще есть типизированные каналы, shared memory, mapped memory и TLS-переменные. Это суть инструмент, на языке которого я выражаю требуемую семантику происходящего. "Простым" способом все эти классы памяти не являются взаимозаменяемые, т.е. если я "просто" размещу переменную в другом классе памяти, то в общем случае изменится семантика программы. Но если компилятор способен проконтролировать все "входы и выходы", побочные эффекты и всякое такое, что в моей голове все-равно не уложится даже в случае средней по размеру программы, то я не против, чтобы он делал любые замены и подстановки, коль заданная мною семантика сохраняется.
Тебя же не смущает, например, что твоя программа, обращающаяся к неким девайсам, в случае работы в виртуалке обращается к их эмулированным моделям? Если тебе обеспечили исходную семантику работы с девайсом, то ничего с твоей программой не случится.
Здравствуйте, vdimas, Вы писали:
V>Покажи, почему разные? Я настаиваю, что семантика переменной чуть более чем полностью определяется ее размещением...
Не стоит настаивать на очевидных заблуждениях. Вы путаете причину и следствие: размещение переменной определяется её семантикой. Компилятор совершенно однозначно принимает решение, что где размещать, на основе информации, которую я ему дал.
Я внёс в программу маленькое изменение, которое вроде бы никак не повлияло на декларацию переменной. И компилятор в ответ послушно изменил её размещение — прозрачным для меня образом.
А ведь мог и не изменять — приведённый фрагмент полностью семантически эквивалентен вот этому:
public void Test()
{
int i = 42;
foreach(var r in Enumerable.Range(1, 5)) {i+= r};
}
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
V>>Покажи, почему разные? Я настаиваю, что семантика переменной чуть более чем полностью определяется ее размещением... S>Не стоит настаивать на очевидных заблуждениях. Вы путаете причину и следствие: размещение переменной определяется её семантикой. Компилятор совершенно однозначно принимает решение, что где размещать, на основе информации, которую я ему дал. S>Я внёс в программу маленькое изменение, которое вроде бы никак не повлияло на декларацию переменной. И компилятор в ответ послушно изменил её размещение — прозрачным для меня образом. S>А ведь мог и не изменять — приведённый фрагмент полностью семантически эквивалентен вот этому: S>
S>public void Test()
S>{
S> int i = 42;
S> foreach(var r in Enumerable.Range(1, 5)) {i+= r};
S>}
S>
Ну давай посмотрим, что изменилось. Если в прошлый раз переменная была доступна из двух локальных фреймов (в том, в котором объявлена, и в том, который замкнул ее by name), то теперь только из одного. Но она как была объявленной локальной переменной, с областью видимости внутри объявленного scope, так и осталась (в предыдущем примере область замыкания была подобластью той, где объявлена переменная). Теперь ближе к конкретике: для первого случая, вместо размещения переменной в локальном (т.е. принадлежащем одному потоку, т.е. однопоточному) фрейме компилятор разместил ее в куче, в некоем специально созданном shared (т.е. доступном из многих потоков) фрейме. Почему? Потому как низлежащая платформа не предоставляет встроенных ср-в, т.е. абстракций, для создания таких фреймов, компилятор их эмулирует на чем может. А почему вообще потребовалось создавать этот фрейм? Наверно от того, что переменная хранится по-значению. Если бы переменная оперировала объектом из кучи, никакого фрейма создавать не надо было, мы просто изменили бы семантику переменной включив ее в замыкание by name, а именно, дали бы доступ к значению объявленной локально переменной некоему "продолжению". Напомню, что изначально by name работало только с иммутабельными объектами и есть теорема, где для случая иммутабельных объектов замыкания by name и by value эквивалентны. Так зачем C# эмулирует локальный фрейм для замыканий даже для случая ссылочных объектов? Ах, ну да... ссылочные переменные у нас мутабельны, поэтому приходится расшаривать м/у локальными фреймами переменных не сам целевой объект, а именно ссылку на него, для сохранения исходной семантики мутабельной ссылки. Вот и всё, что происходит...
Ну и еще пройдусь по т.н. спекулятивным оптимизациям, когда переменная может "уйти" или местно ее размещения измениться, даже без указания расшаривания переменной в замыкании. Потому как вижу спекулирование на этих спекулятивных оптимизациях. Заблуждение тут простое: технологии классической компиляции, т.е. технологии compile-time, не в состоянии выяснить семантическую эквивалентность программы до спекулятивной оптимизации и после. Требуется т.н. спекулятивное, т.е. преждевременное, выполнение кода, что и есть техника суперкомпиляции. Это же совсем не то же самое что и обычная компиляция, хоть присутствует общий корень в слове. Для случая суперкомпиляции программа прогоняется в специальном режиме, т.е. в классическом рантайм и затем просто "пишется ответ". Обсуждать св-ва суперкомпиляции можно гораздо шире, чем только в плане переменных. Например, классический компилятор не вычисляет пользовательские ф-ии, даже если на них поданы значения, известные во время компиляции, а суперкомпилятор — запросто. Он просто может уничтожить целые куски кода, например убрав все эти ф-ии, которые использовал в результате прогона, а не то что изменить одну несчастную переменную. Однако, чтобы там ни происходило, все спекулятивные вычисления, вся эта эмуляция выполнения производятся исключительно по заданной нами семантике с гарантированным ее сохранением. Что и требуется от исправного компилятора.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Да о всё о том же, что l-value это не само значение, а классическая ссылка на него. S>>l-value это все-таки место, а не ссылка. Сам же говорил, что в C нет ссылок
V>Ну так "место" — это и есть отсылка к значению, а не само значение. V>Да, говорил, насчет С, что ссылок нет, а ссылочная семантика есть.
V>Помнишь, что l-value бывает не только во время присвоения по известному адресу, т.е. при присвоении значения переменной, но и вычисляемое? Поэтому не так всё просто с "местом".
Какие проблемы с вычисляемым l-value?
V>>>Ну вот, ты уже согласился с тем, что ссылка — это тоже значение. ЧТД. Осталось ответить на вопрос, почему я могу иметь значение некоторого типа, а переменную этого типа создать не могу? S>>Давай все-таки разграничивать о каких значениях мы говорим. Формально значением ссылки является то, на что она ссылается. Ты же говоришь о неком значении, которое является служебной информацией ссылки. Да, ты можешь создать переменную, которая будет содержать служебную информацию ссылки. Но значением ссылки будет не эта информация, а та, на которую она ссылается посредством этой служебной информации.
V>Это будет "значением по ссылке", именно так его принято называть.
Первый раз слышу.
V>>>Ну коль язык это инструмент, то мне таки надо знать, что же этот инструмент делает. S>>А делать инструмент может нечто значительно отличающееся от языковых терминов. Ты можешь находить некоторые соответствия, но делать по ним выводы о сущностях уровня языка в общем случае неверно.
V>Не может, иначе инструмент станет негоден. Он должен что-то делать согласно спецификации. Причем, сама спецификация, в свою очередь, построена на основе общепринятой терминологии, а не какой-то специальной-абстрактной.
Я не понимаю, на чем ты настаиваешь? Ты же сам говоришь, что переменной в рантайме может не быть. Где в спецификации написано что в рантайме должны быть переменные и что они должны соответствовать языковым переменным?
V>>>Да это не принципиально. Этот прием даже в бусте пользуют, когда надо хранить/копировать/передавать именно ссылку, а не указуемое значение. Главное здесь что — мы оперируем ссылкой, ссылающейся на всё тот же целевой объект, т.е. сохраняем единственно требуемую от ссылки семантику. Остальное никого не интересует. S>>Мы не оперируем ссылкой, мы создаем новую ссылку каждый раз.
V>Именно, только это от ссылки и требуется — при копировании их, не копировать целевое значение. Больше никакой семантической нагрузки они не несут.
Я говорю о том, что значением переменной мы можем оперировать, а ты куда-то уводишь.
V>>>Разве? С каких пор поле объекта перестало быть разновидностью переменной? S>>с тех пор, когда поле объекта стало ссылкой.
V>А что в этом случае страшное произошло? Память не из адреса объекта под ссылочную переменную выделилась или что-то еще?
Ничего такого не произошло, то же что и с локальной ссылкой.
S>>Я уже писал, что ссылка ссылается на место. Это место может быть переменной. А может быть местом в куче.
V>Это ты первый раз в этом посте написал, до этого настаивал исключительно на переменной.
Лень искать, но я писал уже об этом. V>Так по-немногу и доберемся до цели.
S>>Ты опять применяешь термин языка к рантайму. Представь что мы где-то в дебрях рекурсии без хвостовой оптимизации (пусть факториала). Стек кончился. Чем память забита? Да хрен, знает, а живая переменная лишь одна!
V>Если в стеке нет временных переменных, а только адреса возвратов, то сложно не переделать в хвостовую рекурсию... А если там параметры — то они суть классические локальные переменные. "Язык рантайма" тут не при чем.
Э не, ты не путай. Локальная переменная она одна! А чего-там в стеке понапихано — большой вопрос.
V>>>Ну и как можно оперировать константным адресом, с которым я сравнил ссылку? Распечатать его числовое представление для целей отладки? S>>И это тоже. А еще можем взять адрес адреса и куда-нибудь передать.
V>Внимание, вопрос! Зачем это надо для адреса, который константа? (с которым сравнили ссылку) V>Серьезно, аж интересно стало.
Ну так это дело десятое. Серьезно — лень выдумывать. Важно что адрес адреса взять можем, а адрес ссылки — нет.
V>>>ldloc грузит само значение в стек, результатом будет копия значения ссылки на стеке. S>>Значение ссылки — это то место, на которое она ссылается.
V>Это на ЯВУ, а в опкодах CLI — это адрес. После прочтения значения ссылки надо делать ldobj (или как там его)...
Вот видишь в опкодах оказывается и ссылки-то нет, а есть адрес. А ты пытаешься еще какую-то параллель проводить между рантаймом и ЯВУ...
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>А тебя не смущает, что в рантайме может не оказаться того, что ты так старательно и конкретно указывал?
V>Ты имеешь ввиду суперкомпиляцию? Нет, не смущает. У меня на уровне ЯП есть некий инструментарий при работе с памятью: куча, стек, поля составных типов, глобальные (статические) переменные, где-то еще есть типизированные каналы, shared memory, mapped memory и TLS-переменные. Это суть инструмент, на языке которого я выражаю требуемую семантику происходящего. "Простым" способом все эти классы памяти не являются взаимозаменяемые, т.е. если я "просто" размещу переменную в другом классе памяти, то в общем случае изменится семантика программы. Но если компилятор способен проконтролировать все "входы и выходы", побочные эффекты и всякое такое, что в моей голове все-равно не уложится даже в случае средней по размеру программы, то я не против, чтобы он делал любые замены и подстановки, коль заданная мною семантика сохраняется.
Ну т.е. ты признаешь что между рантаймом и ЯВУ параллели может не быть, тем не менее настаиваешь на том, что бы именно по рантайму делать выводы о сущностях ЯВУ?
V>Тебя же не смущает, например, что твоя программа, обращающаяся к неким девайсам, в случае работы в виртуалке обращается к их эмулированным моделям? Если тебе обеспечили исходную семантику работы с девайсом, то ничего с твоей программой не случится.
Так это аргумент против твоих доводов.
Вообще говоря, программа не работает с девайсом. Она работает по большому счету с командами. Даже если в программе есть высокоуровневая абстракция девайса, то эта абстракция лишь в голове разработчика. Ни в рантайме, ни в ЯВУ никакого девайса нет, есть порт и функции чтения/записи данных.
Здравствуйте, samius, Вы писали:
V>>Помнишь, что l-value бывает не только во время присвоения по известному адресу, т.е. при присвоении значения переменной, но и вычисляемое? Поэтому не так всё просто с "местом". S>Какие проблемы с вычисляемым l-value?
Противоречило предыдущим твоим рассуждениям относительно ссылок на переменные.
V>>А что в этом случае страшное произошло? Память не из адреса объекта под ссылочную переменную выделилась или что-то еще? S>Ничего такого не произошло, то же что и с локальной ссылкой.
Не понял ответа. Локальная ссылка на локальную же переменную является константой времени компиляции, как это можно сравнивать с иммутабельным объектом времени исполнения?
V>>Если в стеке нет временных переменных, а только адреса возвратов, то сложно не переделать в хвостовую рекурсию... А если там параметры — то они суть классические локальные переменные. "Язык рантайма" тут не при чем. S>Э не, ты не путай. Локальная переменная она одна! А чего-там в стеке понапихано — большой вопрос.
Нет, не одна, иначе она бы назвалась не локальной, а глобальной. А локальных переменных ровно столько, сколько раз вызвали процедуру, в которой они объявлены. По определению локальной переменной.
V>>Внимание, вопрос! Зачем это надо для адреса, который константа? (с которым сравнили ссылку) V>>Серьезно, аж интересно стало. S>Ну так это дело десятое. Серьезно — лень выдумывать. Важно что адрес адреса взять можем, а адрес ссылки — нет.
Дык, вопрос и стоит, почему для случая указателяконстанты это важно? Нецжели не понял намека на то, что у обычного указателя нам адрес нужен только для мутации значения указателя, например, для передачи как out-параметра в процедуру. Но это не работает для указателя-константы, так что вопрос в силе.
V>>>>ldloc грузит само значение в стек, результатом будет копия значения ссылки на стеке. S>>>Значение ссылки — это то место, на которое она ссылается.
V>>Это на ЯВУ, а в опкодах CLI — это адрес. После прочтения значения ссылки надо делать ldobj (или как там его)... S>Вот видишь в опкодах оказывается и ссылки-то нет, а есть адрес. А ты пытаешься еще какую-то параллель проводить между рантаймом и ЯВУ...
Что я вижу? В опкодах она ссылкой и называется, просто можно взять ее адрес в опкодах, в отличие от. Язык C# позволяет взять адрес только ссылочных переменных, ссылающиеся на managed-объекты в куче (1), но не позволяет брать адреса ссылок на другие типы объектов (2). Например, не позволяет брать адрес ссылки на ссылку типа (1). Это ограничение семантики языка, и я их понимаю... бо и так уже запутанно выходит. Ведь ссылка на объект ref-type в куче во всех сценариях ведет себя как типичный value-type. Одна эта фраза ставит новичков в глубокий ступор... а C# позиционировался малость иначе...
Здравствуйте, vdimas, Вы писали:
V>Однако, чтобы там ни происходило, все спекулятивные вычисления, вся эта эмуляция выполнения производятся исключительно по заданной нами семантике с гарантированным ее сохранением. Что и требуется от исправного компилятора.
Ну вот видите — стоило сделать небольшое умственное усилие, и вам удалось признать мою правоту.
Первична именно семантика переменной, определённая в терминах того языка, на котором эта переменная описывается.
А какие там ухищрения нужно делать на нижележащей платформе, чтобы эту семантику обеспечить — дело десятое. В том числе и размещение переменной. Сегодня компилятор шарпа выделяет closure variables в поля объектов, размещённых в куче. Завтра прикрутят escape-анализ — и он будет оставлять переменную в примерах типа того, который я привел, на стеке.
Или вообще переменную устранит.
Всё это — вторично по отношению к программе.
Когда мы говорим о семантике целых чисел в С++, мы не интересуемся тем, как там должен использоваться бит переноса в регистре флагов. Когда мы говорим о семантике переменных, мы не интересуемся тем, где именно во flat-модели памяти расположена эта переменная.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Помнишь, что l-value бывает не только во время присвоения по известному адресу, т.е. при присвоении значения переменной, но и вычисляемое? Поэтому не так всё просто с "местом". S>>Какие проблемы с вычисляемым l-value?
V>Противоречило предыдущим твоим рассуждениям относительно ссылок на переменные.
Я писал, что ссылки бывают не только на переменные.
V>>>А что в этом случае страшное произошло? Память не из адреса объекта под ссылочную переменную выделилась или что-то еще? S>>Ничего такого не произошло, то же что и с локальной ссылкой.
V>Не понял ответа. Локальная ссылка на локальную же переменную является константой времени компиляции, как это можно сравнивать с иммутабельным объектом времени исполнения?
А локальная ссылка на что-нибудь в куче не является константой времени компиляции.
V>>>Если в стеке нет временных переменных, а только адреса возвратов, то сложно не переделать в хвостовую рекурсию... А если там параметры — то они суть классические локальные переменные. "Язык рантайма" тут не при чем. S>>Э не, ты не путай. Локальная переменная она одна! А чего-там в стеке понапихано — большой вопрос.
V>Нет, не одна, иначе она бы назвалась не локальной, а глобальной. А локальных переменных ровно столько, сколько раз вызвали процедуру, в которой они объявлены. По определению локальной переменной.
storage location-ов столько, сколько раз вызвали процедуру. Причем обратиться процедура может только к одному из них — на текущем фрейме. А переменная — она одна и в ЯВУ.
V>>>Внимание, вопрос! Зачем это надо для адреса, который константа? (с которым сравнили ссылку) V>>>Серьезно, аж интересно стало. S>>Ну так это дело десятое. Серьезно — лень выдумывать. Важно что адрес адреса взять можем, а адрес ссылки — нет.
V>Дык, вопрос и стоит, почему для случая указателяконстанты это важно? Нецжели не понял намека на то, что у обычного указателя нам адрес нужен только для мутации значения указателя, например, для передачи как out-параметра в процедуру. Но это не работает для указателя-константы, так что вопрос в силе.
Вопрос "какой смысл" не имеет отношения к тому, что можно взять адрес указателяконстанты. Мы можем свдинуть int влево на 10000 позиций. Смысла в этом немного, но ведь можем!
V>>>Это на ЯВУ, а в опкодах CLI — это адрес. После прочтения значения ссылки надо делать ldobj (или как там его)... S>>Вот видишь в опкодах оказывается и ссылки-то нет, а есть адрес. А ты пытаешься еще какую-то параллель проводить между рантаймом и ЯВУ...
V>Что я вижу? В опкодах она ссылкой и называется, просто можно взять ее адрес в опкодах, в отличие от. Язык C# позволяет взять адрес только ссылочных переменных, ссылающиеся на managed-объекты в куче (1), но не позволяет брать адреса ссылок на другие типы объектов (2).
Язык C# не позволяет брать адрес ссылочных переменных, ссылающихся на managed-объекты в куче. Передача ссылки по ref-у это не взятие адреса ссылки. V>Например, не позволяет брать адрес ссылки на ссылку типа (1). Это ограничение семантики языка, и я их понимаю... бо и так уже запутанно выходит. Ведь ссылка на объект ref-type в куче во всех сценариях ведет себя как типичный value-type. Одна эта фраза ставит новичков в глубокий ступор... а C# позиционировался малость иначе...
Ссылка на объект ref-type в куче далеко не во всех сценариях ведет себя как типичный value-type. Например, мы не можем взять ее адрес Здесь она себя ведет как нетипичный value-type, содержащий ссылку в качестве поля. Его адрес тоже нельзя взять.
Здравствуйте, Sinclair, Вы писали:
V>>Однако, чтобы там ни происходило, все спекулятивные вычисления, вся эта эмуляция выполнения производятся исключительно по заданной нами семантике с гарантированным ее сохранением. Что и требуется от исправного компилятора. S>Ну вот видите — стоило сделать небольшое умственное усилие, и вам удалось признать мою правоту. S>Первична именно семантика переменной, определённая в терминах того языка, на котором эта переменная описывается. S>А какие там ухищрения нужно делать на нижележащей платформе, чтобы эту семантику обеспечить — дело десятое. В том числе и размещение переменной. Сегодня компилятор шарпа выделяет closure variables в поля объектов, размещённых в куче. Завтра прикрутят escape-анализ — и он будет оставлять переменную в примерах типа того, который я привел, на стеке. S>Или вообще переменную устранит.
Оптимизация на основе escape-анализа — это техника суперкомпиляции, т.е. ближе к технологии рантайм по сути происходящего, бо происходит эмулирование работы программы. Бывает же оптимизациями по показаниям профайлера, например, — тоже лишь техникой compile-time эта задача нерешабельна.
S>Всё это — вторично по отношению к программе.
Почему? Ну, проэмулировал шарп семантику замыкания by value через эмуляцию фрейма в виде объекта на куче, какие проблемы если он сделал это корректно? Мы ведь уже договорились недавно, что даже фреймы под локальные переменные не обязаны жить в "родном" стеке процессора, нас вовсе не подробности реализации фреймов интересуют. Зато интересует факт, что содержимое каждого фрейма должен быть видно лишь одному потоку исполнения (до тех пор, пока некую переменную не заберут в замыкание by name).
S>Когда мы говорим о семантике целых чисел в С++, мы не интересуемся тем, как там должен использоваться бит переноса в регистре флагов. Когда мы говорим о семантике переменных, мы не интересуемся тем, где именно во flat-модели памяти расположена эта переменная.
Ну да, конкретный адрес не важен, а вот обеспечение видимости/локальности, уникальности экземпляра и т.д. — важно, т.е. важно обеспечение неких характеристик, присущим некоему memory storage class, именно оно и составляет семантику (о чем и говорил выше по ветке). Какое-никакое представление/модель происходящего в случае каждого storage class в голове держать надо во время написания программы. Как пример — отличие статического поля от экземплярного поля объекта. Как ни крути, а понимать в чем отличие — придется, даже пусть каждый понимает это отличие по-своему (существует как минимум 2 модели реализации статических полей, в случае их размещения по известным адресам в compile-time или динамически в runtime).
V>>Ты имеешь ввиду суперкомпиляцию? Нет, не смущает. У меня на уровне ЯП есть некий инструментарий при работе с памятью: куча, стек, поля составных типов, глобальные (статические) переменные, где-то еще есть типизированные каналы, shared memory, mapped memory и TLS-переменные. Это суть инструмент, на языке которого я выражаю требуемую семантику происходящего. "Простым" способом все эти классы памяти не являются взаимозаменяемые, т.е. если я "просто" размещу переменную в другом классе памяти, то в общем случае изменится семантика программы. Но если компилятор способен проконтролировать все "входы и выходы", побочные эффекты и всякое такое, что в моей голове все-равно не уложится даже в случае средней по размеру программы, то я не против, чтобы он делал любые замены и подстановки, коль заданная мною семантика сохраняется. S>Ну т.е. ты признаешь что между рантаймом и ЯВУ параллели может не быть, тем не менее настаиваешь на том, что бы именно по рантайму делать выводы о сущностях ЯВУ?
Здравствуйте, vdimas, Вы писали:
V>Оптимизация на основе escape-анализа — это техника суперкомпиляции, т.е. ближе к технологии рантайм по сути происходящего, бо происходит эмулирование работы программы. Бывает же оптимизациями по показаниям профайлера, например, — тоже лишь техникой compile-time эта задача нерешабельна.
Это неважно. Дотнет — среда управляемая, может и в рантайме оптимизировать.
S>>Всё это — вторично по отношению к программе.
V>Почему? Ну, проэмулировал шарп семантику замыкания by value через эмуляцию фрейма в виде объекта на куче, какие проблемы если он сделал это корректно? Мы ведь уже договорились недавно, что даже фреймы под локальные переменные не обязаны жить в "родном" стеке процессора, нас вовсе не подробности реализации фреймов интересуют. Зато интересует факт, что содержимое каждого фрейма должен быть видно лишь одному потоку исполнения (до тех пор, пока некую переменную не заберут в замыкание by name).
Вы опять путаете семантику программы и детали её реализации.
V>Ну да, конкретный адрес не важен, а вот обеспечение видимости/локальности, уникальности экземпляра и т.д. — важно, т.е. важно обеспечение неких характеристик, присущим некоему memory storage class, именно оно и составляет семантику (о чем и говорил выше по ветке).
Зачем вы вводите этот memory storage class, если он не имеет отношения к "настоящей" памяти? И в спецификации языка он тоже не встречается.
V> Какое-никакое представление/модель происходящего в случае каждого storage class в голове держать надо во время написания программы. Как пример — отличие статического поля от экземплярного поля объекта. Как ни крути, а понимать в чем отличие — придется, даже пусть каждый понимает это отличие по-своему (существует как минимум 2 модели реализации статических полей, в случае их размещения по известным адресам в compile-time или динамически в runtime).
В это понимание совершенно не обязаны входить заблуждения типа "статическое поле — это прямой адрес, а экземплярное — это адрес + смещение". Семантика полей в дотнете такова, что статическое поле хранит ровно одно значение в пределах домена, а экземплярное — по значению на каждый экземпляр. Всё. Каким конкретно образом обеспечивается доступ к этим полям — знать необязательно. А зачастую ещё и противопоказано, т.к. провоцирует на написание implementation-dependent кода.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Sinclair, Вы писали:
S>>В это понимание совершенно не обязаны входить заблуждения типа "статическое поле — это прямой адрес, а экземплярное — это адрес + смещение". Семантика полей в дотнете такова, что статическое поле хранит ровно одно значение в пределах домена, а экземплярное — по значению на каждый экземпляр. Всё. Каким конкретно образом обеспечивается доступ к этим полям — знать необязательно. А зачастую ещё и противопоказано, т.к. провоцирует на написание implementation-dependent кода.
V>Извини, коллега, но ты как с другой вселенной. Я прекрасно понимаю, о чем ты, но не верится, что об этом можно вот так всерьез на весь интернет. Особенно когда постоянно приходится работать над быстродействием дотнетных программ. Я понятия не имею, чем вы там на работе занимаетесь, но сколько видел или участвовал в проектах... так вот, "абстрактные" программисты, не понимающие суть происходящего, для более-менее серьезных проектов банально профнепригодны. Не нужны.
"Две основные формы вербального синкретизма — синкретизм рассуждения, проявляющийся во взаимном искажении высказываний, рассматриваемых вместе, и синкретизм понимания, который заключается в том, что понимание текста или фразы начинается не с анализа деталей, а с создания схемы целого, дающей смысл отдельным словам."
Здравствуйте, Sinclair, Вы писали:
S>Для вас — это то, что вы изучили в начале своей "профильной" карьеры. Поэтому все современные абстракции вы пытаетесь сначала перевести на уровень воображаемого вами процессора x86.
Ох, знал бы ты, для скольких я архитектур на асме писал многие годы... Для x86 — меньше всего, если брать именно в асме или низкоуровневые/встраиваемые.
S>Для меня — это семантика, и умение свободно переходить от одного уровня абстракции к другому и обратно.
И какие проблемы? На некоторых архитектурах привычные тебе вещи вообще делаются задом наперед и с очень многими ограничениями. В этих случаях тем более надо понимать, что происходит, чтобы лажи не напороть.
Абстракция позволяет абстрагироваться от подробностей, согласен. Но если ты знаешь, например, что замыкание создаст объект-локальный-фрейм в куче, потом делегат, то будешь пытаться писать код так, чтобы это замыкание не создавалось внути критического цикла мильон раз. Иначе твоя программа банально не взлетит. Ты просто не будешь вылезать из профайлера каждые следующие десяток накиданных строчек кода, работать некогда будет.
S>Моё понимание устройства программы делится на чётко выраженные уровни. Вот у нас уровень архитектуры приложения; вот у нас конструкции ЯП, которые эту архитектуру воплощают; вот MSIL,
Даже уже MSIL не важен, достаточно более крупно: память в куче, в поле объекта, локальная на стеке, статическая. Достаточно иметь представление, какие имеем затраты для каждого из популярных сценариев и можно начинать писать адекватные программы.
S>Благодаря этой отдельности я могу следить, на чём основаны те или иные предположения, и будут ли они оставаться справедливыми при замене того или иного уровня абстракции.
Да ты не можешь ни за чем следить, если не будешь понимать взаимосвязь различных уровней абстракции. И ведь ты прекрасно понимаешь, тем не менее регулярно вижу как ты толкаешь окружающим мантру, что типа это необязательно. А это неправда. Сколько разработчиков в своей жизни видел, столько раз убеждался, что еще как обязательно. Да и любого более-менее опытного разработчика с этого сайта возьми — обидится ведь, если предположить, что он пользуется инструментом не зная практически в совершенстве, как инструмент устроен и работает.
S>Я насмотрелся (да и сам таким был) на людей, которые сращивают все эти слои в голове в монолит. Им крайне некомфортно переходить на другие платформы, т.к. они не понимают границы применимости предположений.
Какие такие другие платформы? Сколько платформ/языков/поколений ты сменил за время своего стажа в IT? Откуда ты вообще мог взять такое странное мнение? Мне пока кажется, что ты споришь с надуманной для самого себя "потенциальной проблемой", которой реально нет и не было. Чем больше понимаешь устройство любой платформы, тем более комфортно под нее программировать. Это тебе по опыту десятка с лишним платформ и архитектур, включая микропрограммные. Для сравнения, из известного тебе: подробно изучал платформу Джаву в 96-м (именно саму платформу, включая JNI), и так и не мог заставить себя юзать это поделие. Первый дотнет показал в 3 раза большую живость аналогичных программ, только поэтому сразу заслужил внимание. Работа GC тоже замерялась с пристрастием в первый же день экспериментов в 2002-м.
S>Мир ведь не исчерпывается только дотнетом на x86. Есть ещё веб-программирование с его стеком AJAX-технологий; там очень многое нужно делать совсем не так, как представляется правильным в дотнетной настольной программе.
Серьезно?
А больше нет никаких областей, где "очень многое нужно делать совсем не так, как представляется правильным в дотнетной настольной программе"? Ну это уже совсем уровень аргументов, мягко говоря...
S>Есть, скажем, базы данных, где зазор между SQL и его физическим планом зачастую значительно сильнее, чем между C++ программой и её скомпилированным представлением.
Это если не владеть реляционной алгеброй и не изучать основные приемы отображения деклараций SQL на примитивы реляционной алгебры в пору своего образования. Тогда план запроса будет для тебя просто темный лес, разумеется, и что делать с индексами, когда делать и почему именно так — ты никогда не поймешь... это же не уровень SQL, это же уже не та абстракция, правильно?
Хороший пример, кстати, насчет SQL, в точку. Там вообще до 2-3-х порядков проседания производительности получить как 2 пальца об асфальт, если не понимать происходящее. Даже такую, казалось бы, мелочь, что есть varchar, а что есть text.
S>И умение переходить от одной СУБД к другой, одновременно представляя себе последствия для производительности, невозможно получить при монолитном представлении о "сути" SQL.
Ровно наоборот.
Не понимая устройства типов данных конкретной СУБД, и правил по их обработке размещению, и не владея реляционной алгеброй, твой SQL превращается в гранату в руках обезъяны. И да, работал не только с MS SQL и Oracle. Хотя и этих достаточно, если сравнивать типы данных и подходы к хранению записей.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Ссылка на объект ref-type в куче далеко не во всех сценариях ведет себя как типичный value-type. Например, мы не можем взять ее адрес
V>Можем в опкодах. А в языке можем создавать ссылку на эту ссылку.
Может в опкодах и можно взять адрес ссылки на управляемый объект, но будет ли такой код верифицирован? Насколько я понимаю, предлагаемое тобой противоречит стабильности работы GC. Да и речь была за C#, а не про опкоды.
Здравствуйте, DarkGray, Вы писали:
DG>так тебе vdimas верно и говорит, что единственно инвариантным утверждением при переходе между разными уровнями абстракции остается то, что переменная использует локальную адресацию с семантикой address := F(context, local-address), причем address — это тоже локальный адрес, но уже в каком-то другом более большом контексте .
Простите, а вы здесь переменной называете что? Variable в терминах спецификации C#? Или какую-то другую сущность, которая внезапно существует одновременно на разных уровнях абстракции?
Что вы называете "локальным адресом"? Чем он отличается от "нелокального"?
Заблуждения про то, что контекстом статической переменной является сборка я обсуждать не буду.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
I>Предположим, есть два объекта которые идентичны согласно твоему определению идентичности. I>Ответь пожалуйста на три вопроса: I>Можно ли в момент времени t+1 послать одному объекту сообщение A, а второму сообщение Б ?
в правильной архитектуре такие объекты с размытой идентичностью используются для задачи, когда нам нет необходимости различать эти объекты. например, пул балансирующих серверов (или пул любых других объектов) может не обладать идентичностью своих элементов для клиента.
но если сильно хочется, то можно отправить и такой вариант сообщения, но при этом оно реально дойдет только в следующий момент времени, когда будет g(t) > 0
I>Если да, то каким образом это возможно, т.к. в момент времени t и все предыдущие эти два объекта идентичны ?
сами по себе объекты идентичны, но в памяти клиента(отправителя сообщения) они могут эмулироваться как различные.
например, при хакерских атаках на те же пулы — такое бывает делают.
опять же бывают самонацеливаемые сообщения. соответственно такое сообщение циркулирует в системе, пока не появится объект с идентичностью Б.
I>Если нет, то нахрена нам нужна такая идентичность ?
потому что в реальной жизни, такая идентичность встречается сплошь и рядом.
например, вещи в магазине из одной партии обладают идентичностью только пока мы с ними находимся в одном физическом пространстве и смотрим на них, в этом момент они различимы по положению в пространстве.
причем даже в этот момент идентичность очень эфемерна, в любой момент эту идентичность может поменять другой человек или естественный ход событий.
в программирование по такому принципу часто работают пулы: объекты в пуле между собой неразличимы, и идентичность одного объекта по отношению к другим объектам из пула появляется только в момент подсоединения клиентского объекта (причем и эта идентичность может быть эфемерной, пуловский объект и в этот момент может быть подменен на другой)
или, например, когда из под одного аккаунта работают два человека, идентичность конкретного человека может появиться только в момент t, только если он сам об этом скажет, или мы как-то догадаемся по характерным особенностям.
S>Что вы называете "локальным адресом"? Чем он отличается от "нелокального"?
для однозначного обращения по локальному адресу необходим контекст относительного которого он резолвится.
для нелокального адреса можно считать, что контекст для всех всегда один и тот же и поэтому его можно опускать.
например, адрес http://rsdn.ru можно считать абсолютным, потому что при передаче другим он будет однозначно отрезолвен (хотя есть ситуации и системы, когда для однозначного резолвинга http://rsdn.ru необходимо будет указать доп. контекст. например, если мы сидим через кэширующий прокси, то для однозначности необходимо дополнительно указывать контекст: обращение идет к кэшу, или обращение идет к реальному серверу).
а адрес /forum/NewMsg.aspx?mid=4531869 — является локальным, и может быть отрезолвен только если указан контекст относительно которого он резолвится (при этом для объектов, который "живут внутри сайта rsdn.ru" — этот адрес может считаться абсолютным, а относительным будет уже NewMsg.aspx?mid=4531869)
S> Если у вас добавление ждого объекта с N состояниями автоматически увеличивает количество термов в N раз, то ваша модель утонет задолго до того, как мы добавим в неё объекты — переходники.
вот именно, поэтому, например, никто в модель (и реальные программы) и не тащит полную идентичности (хотя ты утверждаешь обратное).
например, идентичность того же double-а плавает от задачи к задаче. и даже в разных функциях одной программы double-ы могут с разной величиной epsilon считаться одинаковыми, и соответственно для такой программы никто не расписывает Единую Функцию Идентичности, Умеющую Различать Любые Два Дабла В Любом Контексте, а используется частичная идентичность — когда каждая функция по своему считает, какие даблы различны.
Здравствуйте, DarkGray, Вы писали:
S>> Если у вас добавление ждого объекта с N состояниями автоматически увеличивает количество термов в N раз, то ваша модель утонет задолго до того, как мы добавим в неё объекты — переходники.
DG>вот именно, поэтому, например, никто в модель (и реальные программы) и не тащит полную идентичности (хотя ты утверждаешь обратное). DG>например, идентичность того же double-а плавает от задачи к задаче. и даже в разных функциях одной программы double-ы могут с разной величиной epsilon считаться одинаковыми, и соответственно для такой программы никто не расписывает Единую Функцию Идентичности, Умеющую Различать Любые Два Дабла В Любом Контексте, а используется частичная идентичность — когда каждая функция по своему считает, какие даблы различны.
С каких пор в качестве идентичности стали выступать нетранзитивные отношения?
S>Заблуждения про то, что контекстом статической переменной является сборка я обсуждать не буду.
и это говорит человек, который так же утверждает: S> Я насмотрелся (да и сам таким был) на людей, которые сращивают все эти слои в голове в монолит.
ты либо трусы наден, либо шубу сними... (c)
и кстати утверждение в скобках неверно, монолит в голове как был, так и остался — может лишь в паре мест дал трещину.
есть два отдельных утверждения:
1. контекстом статической переменной является сборка
2. по умолчанию в домен можно загрузить только один экземпляр сборки.
у тебя же эти утверждения срощены в монолит: в домене может быть только один экземпляр статической переменной.
Здравствуйте, DarkGray, Вы писали:
DG>в данном случае, переменной называется сущность, которая остается от 'Variable в терминах спецификации C#' при переходе между всеми абстракциями
Такой сущности нет. При переходе между разными уровнями абстракций переменная из спецификации "превращается" в различные сущности соответствующего уровня. (Корректнее говорить, что "переменной С#", которая определена только на уровне C#, в других уровнях абстракции соответствуют другие сущности — определённые в тех уровнях абстракции).
DG>именно сборка, потому что если одну и ту же сборку удастся загрузить с другим имененем (например, пропатчив ее), то переменных будет две.
Ок, ладно, вы на верном пути, хотя формулировка недостаточно строгая.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали: DG>вот именно, поэтому, например, никто в модель (и реальные программы) и не тащит полную идентичности (хотя ты утверждаешь обратное).
Тащит. Попробуйте применить оператор == к двум даблам.
DG>например, идентичность того же double-а плавает от задачи к задаче. и даже в разных функциях одной программы double-ы могут с разной величиной epsilon считаться одинаковыми, и соответственно для такой программы никто не расписывает Единую Функцию Идентичности, Умеющую Различать Любые Два Дабла В Любом Контексте, а используется частичная идентичность — когда каждая функция по своему считает, какие даблы различны.
Вы по-прежнему путаете идентичность с эквивалентностью. Печально.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>в данном случае, переменной называется сущность, которая остается от 'Variable в терминах спецификации C#' при переходе между всеми абстракциями S>Такой сущности нет.
это из разряда: жопа — есть, а слова — нет (с)
и опять утверждение нестрогое и неверное одновременно, потому что на самое деле оно утверждает: в данном случае для всех существующих трактовок понятия "сущность", такую сущность выделить невозможно.
S> При переходе между разными уровнями абстракций переменная из спецификации "превращается" в различные сущности соответствующего уровня. (Корректнее говорить, что "переменной С#", которая определена только на уровне C#, в других уровнях абстракции соответствуют другие сущности — определённые в тех уровнях абстракции).
верно, но также не смотря на все эти превращения — также остается и неизменное поведение, которое и выделяется в отдельную сущность, которую можно назвать, например, абстрактная переменная.
S> Вы по-прежнему путаете идентичность с эквивалентностью. Печально.
еще более печально, что ты так и не понял, что они различаются только при взгляде из какой-то одной абстракции, как только мы начинаем смотреть сразу с множества разных уровней абстракций, то грань между ними пропадает.
зы
кстати, необходимым качеством отличного программиста является умением выделять неизменное для разных условий.
чую, что с этим качеством есть проблемы.
S>Ок, ладно, вы на верном пути, хотя формулировка недостаточно строгая.
я правильно понимаю, что твоего признания — что следующие утверждение были неверными (и излишне поспешными), мы так и не дождемся?
S> Семантика полей в дотнете такова, что статическое поле хранит ровно одно значение в пределах домена
S> Заблуждения про то, что контекстом статической переменной является сборка я обсуждать не буду.
S>Вы по-прежнему путаете идентичность с эквивалентностью. Печально.
кстати утверждение "Если что-то выглядит как утка, плавает как утка и крякает как утка, то — это утка", как раз фактически и говорит, что из эквивалентности следует идентичность, и для многих ситуаций — это верно.
S>>С каких пор в качестве идентичности стали выступать нетранзитивные отношения?
DG>сначала пруфлинк на то, что идентичность в ООП обязана быть строго транзитивным отношением.
То что идентичность должна являться отношением эквивалентности доказывать надо?
S>>>С каких пор в качестве идентичности стали выступать нетранзитивные отношения?
DG>>сначала пруфлинк на то, что идентичность в ООП обязана быть строго транзитивным отношением. S>То что идентичность должна являться отношением эквивалентности доказывать надо?
если приведешь пруфлинк, что отношение эквивалентности обязано быть строго транзитивным в ООП, то это утверждение приму на веру без доказательства.
зы
кстати для double с функцией сравнения с точностью до epsilon отношение эквивалентности не является строго транзитивным
S>>>>С каких пор в качестве идентичности стали выступать нетранзитивные отношения?
DG>>>сначала пруфлинк на то, что идентичность в ООП обязана быть строго транзитивным отношением. S>>То что идентичность должна являться отношением эквивалентности доказывать надо?
DG>если приведешь пруфлинк, что отношение эквивалентности обязано быть строго транзитивным в ООП, то это утверждение приму на веру без доказательства.
Есть формальное определение отношение эквивалентности и мне не известно ни одного повода считать что его можно ослабить, в том числе для ООП.
DG>зы DG>кстати для double с функцией сравнения с точностью до epsilon отношение эквивалентности не является строго транзитивным
Сравнение с точностью по epsilon не является отношением эквивалентности по определению отношения эквивалентности.
S>Есть формальное определение отношение эквивалентности и мне не известно ни одного повода считать что его можно ослабить, в том числе для ООП.
также посоветую прочитать что-то помимо букваря.
кроме классической эквивалентности из первого класса школы, есть также, например, эквивалентность для нечетких множеств.
соответственно необходимо привести пруфлинк, что в ООП нельзя применять нечеткие множества и соответствующую эквивалентность.
Здравствуйте, samius, Вы писали:
V>>Можем в опкодах. А в языке можем создавать ссылку на эту ссылку. S>Может в опкодах и можно взять адрес ссылки на управляемый объект, но будет ли такой код верифицирован?
Будет.
S>Насколько я понимаю, предлагаемое тобой противоречит стабильности работы GC.
GC не при чем, это стандартная инструкция ldloca. Дизассемблируй любую сборку и посмотри как часто она применяется.
S>Да и речь была за C#, а не про опкоды.
Это да... Но я же уже дал понять, что для меня будет ссылка на эту ссылку. Для меня это и есть тот самый банальный адрес для целей +1 к косвенной адресации, и ничего более.
Собственно, я не сильно различаю "оттенки" ссылочных типов данных (например, указателя и ссылки) и не собираюсь впредь. И спор пора завязывать, позиции друг друга мы поняли. Для меня указатель — это такой же обычный ссылочный тип данных, просто "с плюшками", например, можно посмотреть его двоичное устройство, отсюда его семантика как значения. Конечно, встает вопрос: "а нафига нам смотреть его двоичное устройство?".. хз, но ведь можно же...
Здравствуйте, samius, Вы писали:
V>>Не так. Оптимизация приемами суперкомпиляция — это скорее рантайм, а не compile-time. Посмотри рядом Синклеру чуть подробней обрисовал: http://www.rsdn.ru/forum/philosophy/4523815.1.aspx
S>Для того что бы выкидывать поля, переменные, структуры, функции и т.п. не нужна никакая суперкомпиляция и рантаймы.
Нужна. Например, распространение констант дальше области видимости, например при инлайне и подстановке — это и есть спекулятивные вычисления. Техникой компиляции это нерешабельно, это чистая эмуляция работы программы по заданной изначально семантике. Я не спорю, что джит это может... это ничего неменяет, просто вместо многократных вычислений некоей формулы с параметром-константой, джит вычислил ее однократно. Т.е. он не просто скомпиллировал формулу, а именно что запустил ее на исполнение.
S>Даже если оптимизация выполнена приемами суперкомпиляции, это ничего не меняет в отношении исходного кода и двоичного.
Ну да, только это уже вообще никак не относится к спору о размещении переменных. Забудь тогда про существование переменных как таковых. Например, если ты написал алгоритм, выдающий числа фибоначи, и из main() вызвал его с параметром-константой, то некий суперкомпилятор может просто преобразовать твою программу в последовательность printf(const1), printf(const2) и т.д. Но это не будет подтверждением вашей т.з., ведь переменных уже нет никаких, и самого алгоритма нет. Зато я наставиваю, что эти constX он вычислил по заданной изначально семантике. Причем, вычслил через эмуляцию работы программы, что является классическим рантайм.
Здравствуйте, DarkGray, Вы писали:
V>> Конечно, встает вопрос: "а нафига нам смотреть его двоичное устройство?"..
DG>это обычно необходимо для операции сериализации.
Ну если адрес показывает некое смещение относительно некоей метки сериализуемого блока, то да... а в общем случае, при последующей дессериализации адрес станет невалидный.
Здравствуйте, DarkGray, Вы писали:
V>> Конечно, встает вопрос: "а нафига нам смотреть его двоичное устройство?"..
DG>это обычно необходимо для операции сериализации.
Кстати, вспомнил, что внутри windows младшие биты указателей (нулевые при выровненных данных) используются для защиты от ABA в lock-free алгоритмах...
DG>>кроме классической эквивалентности из первого класса школы, есть также, например, эквивалентность для нечетких множеств. DG>>соответственно необходимо привести пруфлинк, что в ООП нельзя применять нечеткие множества и соответствующую эквивалентность. S>Предлагаю для начала представить пруфлинк что отношение сравнения даблов по эпсилону является отношением нечеткой эквивалентности, в частности что для него выполняется нечеткая транзитивность
согласен. в общем случае, не будет для таких double-ов нечеткого отношения эквивалентности.
в общем случае будет лишь выполняться отношение толерантности.
для появления эквивалентности необходимо округлять на epsilon перед сравнением.
S> Google: No results found for "нестрогое отношение эквивалентности"
DG>>почти нет моделей, которые позволяют описывать эквивалентность моделей(кода). S>Просто удивительно — как же Чёрч с Тьюрингом ухитрились договориться.
Здравствуйте, DarkGray, Вы писали:
S>>Предлагаю для начала представить пруфлинк что отношение сравнения даблов по эпсилону является отношением нечеткой эквивалентности, в частности что для него выполняется нечеткая транзитивность
DG>согласен. в общем случае, не будет для таких double-ов нечеткого отношения эквивалентности. DG>в общем случае будет лишь выполняться отношение толерантности. DG>для появления эквивалентности необходимо округлять на epsilon перед сравнением.
Не понял, это как?
S>> Google: No results found for "нестрогое отношение эквивалентности"
DG>тогда ищи что такое отношение толерантности
А какое отношение имеет толерантность к идентичности?
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Не так. Оптимизация приемами суперкомпиляция — это скорее рантайм, а не compile-time. Посмотри рядом Синклеру чуть подробней обрисовал: http://www.rsdn.ru/forum/philosophy/4523815.1.aspx
S>>Для того что бы выкидывать поля, переменные, структуры, функции и т.п. не нужна никакая суперкомпиляция и рантаймы.
V>Нужна. Например, распространение констант дальше области видимости, например при инлайне и подстановке — это и есть спекулятивные вычисления. Техникой компиляции это нерешабельно, это чистая эмуляция работы программы по заданной изначально семантике. Я не спорю, что джит это может... это ничего неменяет, просто вместо многократных вычислений некоей формулы с параметром-константой, джит вычислил ее однократно. Т.е. он не просто скомпиллировал формулу, а именно что запустил ее на исполнение.
Тот же инлайн — это не суперкомпиляция, но пример того что суперкомпиляция не нужна для того что бы выкинуть функцию.
S>>Даже если оптимизация выполнена приемами суперкомпиляции, это ничего не меняет в отношении исходного кода и двоичного.
V>Ну да, только это уже вообще никак не относится к спору о размещении переменных. Забудь тогда про существование переменных как таковых. Например, если ты написал алгоритм, выдающий числа фибоначи, и из main() вызвал его с параметром-константой, то некий суперкомпилятор может просто преобразовать твою программу в последовательность printf(const1), printf(const2) и т.д. Но это не будет подтверждением вашей т.з., ведь переменных уже нет никаких, и самого алгоритма нет. Зато я наставиваю, что эти constX он вычислил по заданной изначально семантике. Причем, вычслил через эмуляцию работы программы, что является классическим рантайм.
Алгоритм есть, переменные есть (если с их помощью описан алгоритм). А то что после суперкомпиляции не осталось переменных — как раз и подтверждает ту точку зрения что делать выводы о сущностях программы по сущностям времени выполнения наивно.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Можем в опкодах. А в языке можем создавать ссылку на эту ссылку. S>>Может в опкодах и можно взять адрес ссылки на управляемый объект, но будет ли такой код верифицирован?
V>Будет.
S>>Насколько я понимаю, предлагаемое тобой противоречит стабильности работы GC.
V>GC не при чем, это стандартная инструкция ldloca. Дизассемблируй любую сборку и посмотри как часто она применяется.
Если ты про передачу ссылки by ref, то это не взятие адреса ссылки. Взятие, но лишь для того, что бы передать ссылку by ref. На сколько я понимаю, рантайм заботится о том, что бы адрес ссылки не мог бы взяться для любых других целей.
S>>Да и речь была за C#, а не про опкоды.
V>Это да... Но я же уже дал понять, что для меня будет ссылка на эту ссылку. Для меня это и есть тот самый банальный адрес для целей +1 к косвенной адресации, и ничего более.
Это я понял.
V>Собственно, я не сильно различаю "оттенки" ссылочных типов данных (например, указателя и ссылки) и не собираюсь впредь. И спор пора завязывать, позиции друг друга мы поняли. Для меня указатель — это такой же обычный ссылочный тип данных, просто "с плюшками", например, можно посмотреть его двоичное устройство, отсюда его семантика как значения. Конечно, встает вопрос: "а нафига нам смотреть его двоичное устройство?".. хз, но ведь можно же...
Вообще говоря, сначала был указатель, а потом уж ссылка, которая вроде как указатель, но с другой семантикой. Согласен, пора завязывать.
Здравствуйте, DarkGray, Вы писали:
DG>>>для появления эквивалентности необходимо округлять на epsilon перед сравнением. S>>Не понял, это как?
DG>есть стандартная формула Round(x, точность) = точность * Round(x/точность)
Да, это обеспечит транзитивность.
DG>>>тогда ищи что такое отношение толерантности S>>А какое отношение имеет толерантность к идентичности?
DG>все тоже самое, что необходим пруфлинк, что идентичность должна быть Единой для всего пространства объектов в ООП.
Я просто не представляю, как может быть иначе. Опять подвох с транзитивностью?
DG>если берется сумма множеств с отношениями эквивалентности на каждом, то суммарное множество обладает в общем случае лишь отношением толерантности. DG>тоже самое с идентичностью, если берется сумма множеств с отношением идентичности на каждом, то суммарное множество обладает лишь свойством нетранзитивной идентичности.
Не знаю такой "нетранзитивной идентичности".
DG>это кстати активно используется в реальных ООП-языках, например, для null. нетипизированный null (или константный null) идентичен типизированному null, но null-и разных типов не идентичны друг другу. и это полностью соответствует выше написаному (внутри отдельных множеств строгая идентичность и эквивалентность вводится, но поверх всех множества объекта уже нет): внутри объектов одного типа идентичность транзитивная, но при этом между объектами разных типов транзитивность уже нарушается. соответственно также может вводится типы, для которых строгая идентичность есть только на подмножествах объектов данного типа.
Я вообще не понимаю, о чем речь. Идентичность в C# определена через storage location, для проверки идентичености используется Object.ReferenceEquals (по определению идентичностии ECMA). Соответсвенно, объекты разных типов не могут быть друг другу идентичны. null любого типа идентичен любому другому null.
S>Я вообще не понимаю, о чем речь. Идентичность в C# определена через storage location, для проверки идентичености используется Object.ReferenceEquals (по определению идентичностии ECMA). Соответсвенно, объекты разных типов не могут быть друг другу идентичны. null любого типа идентичен любому другому null.
опять же это идентичность только на подмножестве всех объектов, потому что еще есть value-типы.
и следующий код выдает что-то странное, и соответственно Object.ReferenceEquals не является функцией идентичности, потому что не обладает свойством рефлексивности
int y = 2;
Console.WriteLine(Object.ReferenceEquals(y, y));
Здравствуйте, DarkGray, Вы писали:
S>>Я вообще не понимаю, о чем речь. Идентичность в C# определена через storage location, для проверки идентичености используется Object.ReferenceEquals (по определению идентичностии ECMA). Соответсвенно, объекты разных типов не могут быть друг другу идентичны. null любого типа идентичен любому другому null.
DG>опять же это идентичность только на подмножестве всех объектов, потому что еще есть value-типы.
Для которых идентичность определена по-другому той же ECMA.
DG>и следующий код выдает что-то странное, и соответственно Object.ReferenceEquals не является функцией идентичности, потому что не обладает свойством рефлексивности DG>
DG> int y = 2;
DG> Console.WriteLine(Object.ReferenceEquals(y, y));
DG>
DG>
DG>False
DG>
Она является функцией идентичности по ECMA для ссылочных типов.
DG>>опять же это идентичность только на подмножестве всех объектов, потому что еще есть value-типы. S>Для которых идентичность определена по-другому той же ECMA.
т.е. в С# нет единой функции идентичности? и соответственно, C# не является ООП-языком, т.к. ранее тот же Sinclair утверждан, что в ООП функция идентичности должна быть одна.
DG>>>опять же это идентичность только на подмножестве всех объектов, потому что еще есть value-типы. S>>Для которых идентичность определена по-другому той же ECMA.
DG>т.е. в С# нет единой функции идентичности?
Нет, но ее легко определить. DG>и соответственно, C# не является ООП-языком, т.к. ранее тот же Sinclair утверждан, что в ООП функция идентичности должна быть одна.
Вот тут немного непонятно. Что будет если функций будет 10 и все они будут давать одинаковый результат?
Здравствуйте, DarkGray, Вы писали:
S>>Для которых идентичность определена по-другому той же ECMA.
DG>каким же образом? и является ли при этом это отношением транзитивным?
Побитовым сравнением. Да, транзитивность выполняется.
DG>>т.е. в С# нет единой функции идентичности? S>Нет, но ее легко определить.
определи, пожалуйста, раз это легко сделать.
DG>>и соответственно, C# не является ООП-языком, т.к. ранее тот же Sinclair утверждан, что в ООП функция идентичности должна быть одна. S>Вот тут немного непонятно. Что будет если функций будет 10 и все они будут давать одинаковый результат?
тогда это одна и та же функция, только записанная десять раз.
S>Я вообще не понимаю, о чем речь. Идентичность в C# определена через storage location, для проверки идентичености используется Object.ReferenceEquals (по определению идентичностии ECMA). Соответсвенно, объекты разных типов не могут быть друг другу идентичны. null любого типа идентичен любому другому null.
кстати, мне кажется, что ты мне баки заливаешь — подменяя индентичность объектов на индентичность ссылок.
Identity allows comparison of references. Two references can be compared whether they are equal or not. Due to the identity property, this comparison has special properties. If the comparison of references indicates that the references are equal, then it's clear that the two objects pointed by the references are the same object. If the references do not compare equal, then it's not necessarily guaranteed that the identity of the objects behind those references is different. The object identity of two objects of the same type is the same, if every change to either object is also a change to the other object.
object.ReferenceEquals не удовлетворяет выделенному, соответственно она не является функции идентичности в ООП-понимании
Здравствуйте, DarkGray, Вы писали:
DG>>>каким же образом? и является ли при этом это отношением транзитивным? S>>Побитовым сравнением. Да, транзитивность выполняется.
DG>я правильно, что ты утверждаешь, что struct{int x} идентично struct{float x}?
ECMA-335 8.2.5.1 Identity
The identity operator is defined by the CTS as follows.
• If the values have different exact types, then they are not identical.
• Otherwise, if their exact type is a value type, then they are identical if and only if the bit
sequences of the values are the same, bit by bit.
• Otherwise, if their exact type is a reference type, then they are identical if and only if the
locations of the values are the same.
Identity is implemented on System.Object via the ReferenceEquals method.
DG>>>т.е. в С# нет единой функции идентичности? S>>Нет, но ее легко определить.
DG>определи, пожалуйста, раз это легко сделать.
Пардон, с наскоку не получилось сравнить структуры побитово.
DG>>>и соответственно, C# не является ООП-языком, т.к. ранее тот же Sinclair утверждан, что в ООП функция идентичности должна быть одна. S>>Вот тут немного непонятно. Что будет если функций будет 10 и все они будут давать одинаковый результат?
DG>тогда это одна и та же функция, только записанная десять раз.
Здравствуйте, DarkGray, Вы писали:
S>>Я вообще не понимаю, о чем речь. Идентичность в C# определена через storage location, для проверки идентичености используется Object.ReferenceEquals (по определению идентичностии ECMA). Соответсвенно, объекты разных типов не могут быть друг другу идентичны. null любого типа идентичен любому другому null.
DG>кстати, мне кажется, что ты мне баки заливаешь — подменяя индентичность объектов на индентичность ссылок.
С этим к ECMA.
DG>http://en.wikipedia.org/wiki/Identity_(object-oriented_programming)
DG>
DG>Identity allows comparison of references. Two references can be compared whether they are equal or not. Due to the identity property, this comparison has special properties. If the comparison of references indicates that the references are equal, then it's clear that the two objects pointed by the references are the same object. If the references do not compare equal, then it's not necessarily guaranteed that the identity of the objects behind those references is different. The object identity of two objects of the same type is the same, if every change to either object is also a change to the other object.
DG>object.ReferenceEquals не удовлетворяет выделенному, соответственно она не является функции идентичности в ООП-понимании
А можно продемонстрировать как нарушается выделенное?
DG>> The object identity of two objects of the same type is the same, if every change to either object is also a change to the other object.
DG>>object.ReferenceEquals не удовлетворяет выделенному, соответственно она не является функции идентичности в ООП-понимании S>А можно продемонстрировать как нарушается выделенное?
нарушается, уже банально на строках:
string y = "2";
Console.WriteLine(Object.ReferenceEquals(y, y));
Console.WriteLine(Object.ReferenceEquals(y + "1", y + "1"));
выдает
True
False
после применения одного и того же изменения, идентичные объекты перестали быть идентичными.
DG>>> The object identity of two objects of the same type is the same, if every change to either object is also a change to the other object.
DG>>>object.ReferenceEquals не удовлетворяет выделенному, соответственно она не является функции идентичности в ООП-понимании S>>А можно продемонстрировать как нарушается выделенное?
DG>нарушается, уже банально на строках: DG>
DG> string y = "2";
DG> Console.WriteLine(Object.ReferenceEquals(y, y));
DG> Console.WriteLine(Object.ReferenceEquals(y + "1", y + "1"));
DG>
DG>выдает DG>
DG>True
DG>False
DG>
DG>после применения одного и того же изменения, идентичные объекты перестали быть идентичными.
Здесь ничто не изменилось
DG>>>> The object identity of two objects of the same type is the same, if every change to either object is also a change to the other object.
DG>>после применения одного и того же изменения, идентичные объекты перестали быть идентичными. S>Здесь ничто не изменилось
как только в выделенном найдешь (или в другом месте текста про identity), что change объекта не имеет права создавать новые копии объекта, тогда продолжим разговор.
DG>>>>> The object identity of two objects of the same type is the same, if every change to either object is also a change to the other object.
DG>>>после применения одного и того же изменения, идентичные объекты перестали быть идентичными. S>>Здесь ничто не изменилось
DG>как только в выделенном найдешь (или в другом месте текста про identity), что change объекта не имеет права создавать новые копии объекта, тогда продолжим разговор.
В выделенном не об этом. Где-нибудь в другом месте текста про identity по той ссылке тоже об этом нет. Ну а кроме этого, в твоем примере нет и намека на попытку изменения объекта.
Здравствуйте, vdimas, Вы писали:
V>А не преподавали "четкого разделения слоев". И самостоятельно в учебниках не видел.
А вот нам как раз преподавали. У меня просто профильная специальность никакого отношения к программированию не имеет.
А на квантовой оптике обучают математике и физике, и чётко проводят границы между моделями.
V>И ты пока тоже ничего не сформулировал. И под вопросом вообще разделение слоев абстракций, бо в классике абстракции — это градиент, коль не задано обратное, где на одном из полюсов используется минимум деталей, а на другом максимум.
Ну откуда же может взяться градиент в заведомо дискретном множестве?
V>Нет никаких слоев, заданных свыше. "Слои абстракций" бывают в рамках конкретного проекта/продукта, и они могут выбираться на усмотрение разработчиков.
Конечно. Тем не менее, границы между слоями (в приличной архитектуре) чётко выражены.
ограничений на этот счет нет. Назначение этой абстракции ровно одно — объяснять суть происходящего, опуская несущественные детали. А ты почему-то решил, что абстракции нужны исключительно для сокрытия деталей.
Нет, я так не решил.
V>Ладно. Плохой признак, когда к профайлеру приходится часто обращаться.
Конечно плохой — это означает, что вы профилируете невовремя, т.е. занимаетесь premature optimization.
Я, кстати, под профайлером в данном контексте понимаю не конкретное приложение, а вообще измерение производительности — это чтобы избежать ненужных споров. Я полностью согласен с вашей критикой профайлеров и с тем, что специальным образом проведённые тесты — это круто и правильно.
А вот с тем, что умственное моделирование производительности лучше, чем измерение, я не соглашусь.
V>Мде? ну я бы не стал этим хвастаться. У меня в 100% случаев первоначальные предположения совпадают как с с данными профайлера, так и с разницей тестов на производительности...
Искренне завидую. Жаль, что таких людей в природе больше нет. V>Приемов-то оптимизации не так много в природе, овладел ими еще в прошлом веке. И обратное тоже верно — потенциальных типов узких мест (грубо говоря — антипаттернов) очень мало в природе. И они сразу бросаются в глаза. Профалер тут хорош лишь в деле расстановки приоритетов перед началом зачистки этого мусора и то, весьма приблизительно. Бо в конкретном некоем сценарии профалер покажет одну частоту вызовов "узких мест" (например, маленькую), а реально она может вызываться чуть чаще... Поэтому когда речь идет всерьез, то собирается статистика в логах прямо из "боевого" применения, где ни о каких профайлерах речи быть не может...
Можете продемонстрировать на простом примере? Вот в этой несложной программе, где именно боттлнек (чур, профайлер не запускать):
public static void Main()
{
while (true)
{
Console.Write("Enter rack (use '?' for blank): ");
string rack = Console.ReadLine();
if (rack == "")
break;
Console.WriteLine("{0} : {1}", rack, SearchDictionary(rack).Join());
foreach (char c in"ABCDEFGHIJKLMNOPQRSTUVWXYZ")
Console.WriteLine("{0}+{1} : {2}", rack, c, SearchDictionary(rack + c).Join());
}
}
private static string Join(this IEnumerable<string> strs)
{
return string.Join(" ", strs.ToArray());
}
private static string Canonicalize(string s)
{
char[] chars = s.ToUpperInvariant().ToCharArray();
Array.Sort(chars);
return new string(chars);
}
private static IEnumerable<string> SearchDictionary(string originalRack)
{
const string dictionary = @"d:\twl06.txt";
// Calculate all the possible distinct values for the rack.
// As an optimization, stuff the resulting racks in an array so
// that we do not recalculate them during the query. var racks = (from rack in ReplaceQuestionMarks(originalRack)
select Canonicalize(rack)).Distinct().ToArray();
// Check every line in the dictionary to see if it matches
// any possible rack. As an optimization, do an early
// out if the line length does not match the query length. return from line in FileLines(dictionary)
where line.Length == originalRack.Length
where racks.Contains(Canonicalize(line))
select line;
}
private static IEnumerable<string> ReplaceQuestionMarks(string s)
{
int index = s.IndexOf('?');
if (index == -1)
{
yield return s;
yield break;
}
foreach (char c in"ABCDEFGHIJKLMNOPQRSTUVWXYZ")
{
string s2 = s.Substring(0, index) + c.ToString() + s.Substring(index + 1);
foreach (string result in ReplaceQuestionMarks(s2))
yield return result;
}
}
private static IEnumerable<string> FileLines(string filename)
{
using (var sr = File.OpenText(filename))
{
while (true)
{
string line = sr.ReadLine();
if (line == null)
yield break;
yield return line;
}
}
}
Это программа для игры в скрэббл. Она грузит примерно двухмегабайтный файл со словарём английских слов (путь к файлу захардкожен) и выполняет поиск слова, которое можно собрать из заданных ей на входе букв (нужно использовать все предоставленные буквы).
Она чудовищно неоптимальна. V>Наверно, потому что в первую очередь при поднятии производительности умудряюсь множество shared-сценариев свести к local...
Это замечательно. V>Потому что этот уровень настолько далеко отстоит в сравнении с затратами на создание делегата и глобальной блокировкой общего мьютекса на все потоки... что это будет явная профанация, рядом с дотнетными замыканиями обсуждать такие вещи. Просто ты ведь не в курсе, наверно, про эту общую для всех потоков блокировку при создании экземпляра делегата, помимо собственно затратной операции создания делегата, отсюда неуместные рассуждения о приемах, которые на несколько порядков дают меньший прирост, чем простое избавление от делегата... (хоть они тоже в ходу в кач-ве приемов оптимизации.. но уже на совсем другой итерации работ по оптимизации, даже не второй и не третьей)... ИМХО, отсюда и 90% твоих ошибок в первоначальных предположениях. Можно продолжать игнорировать тонкости реализации и дальше.
Не, я не в курсе про эту общую для всех потоков блокировку. А где можно про неё прочитать? Уж очень фантастически звучит.
V>У меня нет границ вообще.
Это я вижу.
V>Про индексы речь шла в деле понимания плана запросов. А сам план запросов как раз в терминах реляционной алгебры отображается.
Неужели? Ну, значит, моё понимание РА сильно отстало от жизни. Когда я в последний раз к ней обращался, там не было никаких Bookmark Lookup, Table Rewind, Clustered Index Seek и прочего.
V>И да, когда изучают реляционную алгебру, то непременно проходят операцию "проекция", сохранением результата которой и является индекс в классике.
Простите, но это чушь. То, что получается в результате выполнения проекции, даже если его сохранить, никак не может быть индексом в классике. Если вам очень хочется поспорить про это — попробуйте применить такой "индекс" для оптимизации какого-нибудь запроса.
Скажем, вот у нас табличка
create table person(id int identity primary key, name varchar(max) not null, gender char(1) not null, picture )
Мы хотим оптимизировать запрос
select id from person where name = 'vdimas'
Расскажите мне, результат какой операции "проекция" тут поможет так же, как
create index ByName on person(name, id)
V>Так не стоит упускать из виду, что реляционная алгебра существует не сама по себе, а как инструмент над реляционной моделью, т.е. другие свои характеристики, например уникальность/неуникальность, индексы берут из раздела реляционной модели данных, которая, анпример, оперирует понятиями основного и альтернативных ключей. И да, понятие индекса идет вместе с реляционными базами данных, для которых, собственно, и была разработана реляционная модель.
Бррр. Опять каша. Реляционная алгебра — это раздел математики, достаточно строго определённый. Она работает с реляциями.
V>Несвязный набор слов. Одно использует другое. SQL оперирует терминами реляционного исчисления, но стоимость операций реляционного исчисления недетерминирована.
Это у вас несвязный набор слов. SQL отклоняется от реляционной алгебры, т.к. представляет компромисс между математической строгостью и вопросами реальной производительности. Терминами реляционного исчисления SQL никак не оперирует:
The current ISO SQL standard doesn't mention the relational model or use relational terms or concepts.
(http://en.wikipedia.org/wiki/Relational_model)
Вопросы стоимости операций появляются только в тот момент, когда мы заменяем абстрактные операции расширенной РА в логическом плане запроса конкретными операциями физического плана запроса. Именно в этот момент появляется простор для оптимизаций, т.к. одному и тому же логическому плану запроса может соответствовать много различных физических планов запроса, отличающихся стоимостью.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>как только в выделенном найдешь (или в другом месте текста про identity), что change объекта не имеет права создавать новые копии объекта, тогда продолжим разговор. S>В выделенном не об этом. Где-нибудь в другом месте текста про identity по той ссылке тоже об этом нет. S> Ну а кроме этого, в твоем примере нет и намека на попытку изменения объекта.
это не формально. введи формальное определение в виде: изменение называется ..., а данная операция этому определению не удовлетворяет.
зы
более сложный пример на тоже самое. есть два объекта y, z, потом они меняются на одно и тоже — и становятся не одинаковыми
string y = "2";
string z = y;
Console.WriteLine(Object.ReferenceEquals(z, y));
y += "1";
z += "1";
Console.WriteLine(Object.ReferenceEquals(z, y));
Здравствуйте, samius, Вы писали:
S>Алгоритм есть, переменные есть (если с их помощью описан алгоритм). А то что после суперкомпиляции не осталось переменных — как раз и подтверждает ту точку зрения что делать выводы о сущностях программы по сущностям времени выполнения наивно.
Да не наивно ни разу. Конечный результат все-равно получен ч помощью заданной нами семантике. А какие уж там преобразования сделает суперкомпилятор — это темный лес. Тем более, что для поданной константы он сделает эти преобразования, а для данных времени исполнения — фиг там... Вот и вернулись к начальной точке.
DG>>>как только в выделенном найдешь (или в другом месте текста про identity), что change объекта не имеет права создавать новые копии объекта, тогда продолжим разговор. S>>В выделенном не об этом. Где-нибудь в другом месте текста про identity по той ссылке тоже об этом нет. S>> Ну а кроме этого, в твоем примере нет и намека на попытку изменения объекта.
DG>это не формально. введи формальное определение в виде: изменение называется ..., а данная операция этому определению не удовлетворяет.
Какая операция? Какому определению?
DG>зы DG>более сложный пример на тоже самое. есть два объекта y, z,
Объект один. И первый ReferenceEquals указывает на это.
DG>потом они меняются на одно и тоже — и становятся не одинаковыми
Объект не меняется, меняются ссылки. DG>
DG> string y = "2";
DG> string z = y;
DG> Console.WriteLine(Object.ReferenceEquals(z, y));
DG> y += "1";
DG> z += "1";
DG> Console.WriteLine(Object.ReferenceEquals(z, y));
DG>
После изменения значений переменных, ссылки, которые в них хранятся, больше не указывают на один и тот же объект.
Что ты пытаешься опровергнуть этим примером? Что RefEquals не может выступать в роли критерия идентичности?
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Алгоритм есть, переменные есть (если с их помощью описан алгоритм). А то что после суперкомпиляции не осталось переменных — как раз и подтверждает ту точку зрения что делать выводы о сущностях программы по сущностям времени выполнения наивно.
V>Да не наивно ни разу. Конечный результат все-равно получен ч помощью заданной нами семантике.
Результат работы программы — да. V>А какие уж там преобразования сделает суперкомпилятор — это темный лес.
Именно поэтому я и настаиваю на том, что результат компиляции не является основой для выводов о сущностях программы. V>Тем более, что для поданной константы он сделает эти преобразования, а для данных времени исполнения — фиг там... Вот и вернулись к начальной точке.
Даже для константы компилятор преобразования может сделать, а может и нет (может зависеть от параметров компиляции). Для времени исполнения — тоже не фиг там. Компилятор обязан обеспечить результат работы программы, но не сохранность сущностей ЯВУ.
DG>>>>> The object identity of two objects of the same type is the same, if every change to either object is also a change to the other object.
DG>>>после применения одного и того же изменения, идентичные объекты перестали быть идентичными. S>>Здесь ничто не изменилось
DG>как только в выделенном найдешь (или в другом месте текста про identity), что change объекта не имеет права создавать новые копии объекта, тогда продолжим разговор.
Операция конкатенации строк не вызывает изменение строк.
var y = "0";
var x = y;
Console.WriteLine(object.ReferenceEquals(x,y)); //Truevar z = y+"1";
Console.WriteLine(object.ReferenceEquals(x,y)); //все равно True
DG>>>как только в выделенном найдешь (или в другом месте текста про identity), что change объекта не имеет права создавать новые копии объекта, тогда продолжим разговор. S>>В выделенном не об этом. Где-нибудь в другом месте текста про identity по той ссылке тоже об этом нет. S>> Ну а кроме этого, в твоем примере нет и намека на попытку изменения объекта.
DG>это не формально. введи формальное определение в виде: изменение называется ..., а данная операция этому определению не удовлетворяет.
DG>зы DG>более сложный пример на тоже самое. есть два объекта y, z, потом они меняются на одно и тоже — и становятся не одинаковыми DG>
DG> string y = "2";
DG> string z = y;
DG> Console.WriteLine(Object.ReferenceEquals(z, y));
DG> y += "1";
DG> z += "1";
DG> Console.WriteLine(Object.ReferenceEquals(z, y));
DG>
DG>выдача DG>
DG>True
DG>False
DG>
string y = "2";
string z = y;
string y1 = y;string z1 = z;
Console.WriteLine(Object.ReferenceEquals(z, y));
y += "1";
z += "1";
Console.WriteLine(Object.ReferenceEquals(z, y));
Console.WriteLine(Object.ReferenceEquals(z1, y1));//Ну ты понял ;)
Здравствуйте, Sinclair, Вы писали:
V>>И ты пока тоже ничего не сформулировал. И под вопросом вообще разделение слоев абстракций, бо в классике абстракции — это градиент, коль не задано обратное, где на одном из полюсов используется минимум деталей, а на другом максимум. S>Ну откуда же может взяться градиент в заведомо дискретном множестве?
Кстати, вот типичная игра понятиями.
Цветовой градиент, он ведь в наших компьютерных реалиях тоже всегда по дискретному множеству. Не смущает?
S>После изменения значений переменных, ссылки, которые в них хранятся, больше не указывают на один и тот же объект.
как ты узнал, что они больше не ссылаются на один и тот же объект?
через ReferenceEquals? т.е. ты ReferenceEquals используешь и для проверки, что ссылки остались теми же, и для определения идентичности объектов?
но в определение явно указано, что это две разных функции: функция сравнения ссылок и функция проверки идентичности
S> Что RefEquals не может выступать в роли критерия идентичности?
конечно, потому что сравнение ссылок, а не сравнение объектов, что и следует из названия
G> string y = "2";
G> string z = y;
G> string y1 = y;
G> string z1 = z;
G> Console.WriteLine(Object.ReferenceEquals(z, y));
G> y += "1";
G> z += "1";
G> Console.WriteLine(Object.ReferenceEquals(z, y));
G> Console.WriteLine(Object.ReferenceEquals(z1, y1));//Ну ты понял ;)
G>
твое "ну, понял" справедливо только при следующих утверждениях:
1) y1 и y (а также z1 и z) — это один и тот же объект
2) y до изменения и y после (а также z) — это разные объекты
на основании чего ты сделал все эти выводы?
на основе внутреннего знания как устроены строки в .net?
тогда ты нарушил принцип инкапсуляции, и это уже никакого отношения к ООП не имеет.
G>> string y = "2";
G>> string z = y;
G>> string y1 = y;
G>> string z1 = z;
G>> Console.WriteLine(Object.ReferenceEquals(z, y));
G>> y += "1";
G>> z += "1";
G>> Console.WriteLine(Object.ReferenceEquals(z, y));
G>> Console.WriteLine(Object.ReferenceEquals(z1, y1));//Ну ты понял ;)
G>>
DG>твое "ну, понял" справедливо только при следующих утверждениях: DG>1) y1 и y (а также z1 и z) — это один и тот же объект
Присваивание ссылок очевидно сохраняет identity.
DG>2) y до изменения и y после (а также z) — это разные объекты
Да, это настолько очевидно что я даже не написал код для проверки
DG>на основании чего ты сделал все эти выводы? DG>на основе внутреннего знания как устроены строки в .net? DG>тогда ты нарушил принцип инкапсуляции, и это уже никакого отношения к ООП не имеет.
Я сделал это на основании того что строки в .NET это reference типы, других соображений не нужно.
Хотя сведения о том что += не изменяет строку есть в MSDN, только инкапсуляцию это никак не нарушает.
Здравствуйте, DarkGray, Вы писали:
S>>После изменения значений переменных, ссылки, которые в них хранятся, больше не указывают на один и тот же объект.
DG>как ты узнал, что они больше не ссылаются на один и тот же объект?
ReferenceEquals
DG>через ReferenceEquals? т.е. ты ReferenceEquals используешь и для проверки, что ссылки остались теми же, и для определения идентичности объектов?
Совершенно верно. Identity is implemented on System.Object via the ReferenceEquals method. (ц)
DG>но в определение явно указано, что это две разных функции: функция сравнения ссылок и функция проверки идентичности
Вообще говоря — это разные функции в широком смысле. Но разве что-то мешает определять одну через другую?
S>> Что RefEquals не может выступать в роли критерия идентичности?
DG>конечно, потому что сравнение ссылок, а не сравнение объектов, что и следует из названия
А из ECMA следует что идентичность реализована через сравнение ссылок. И именно это определяет, где один объект, а где другой.
DG>>>определи, пожалуйста, раз это легко сделать.
S>>Пардон, с наскоку не получилось сравнить структуры побитово.
DG>тогда из этого следует, что Ecma identity не может использоваться как функция идентификации объектов,
Я походу пропустил какое-то звено в рассуждениях. Следствие для меня неочевидно.
Не получилось у меня именно сравнение по memcmp структур, содержащих ссылки. Это не значит, что сравнение структур побитово невыполнимо.
DG>потому что она нарушает инкапсуляцию объектов.
А разве есть какая-то связь?
DG>>твое "ну, понял" справедливо только при следующих утверждениях: DG>>1) y1 и y (а также z1 и z) — это один и тот же объект G>Присваивание ссылок очевидно сохраняет identity.
как только появляется слово "очевидно", то это означает, что человек не может объяснить происходящее.
откуда известно, что в данном месте происходит присвоение ссылок, а не что-то другое?
DG>>2) y до изменения и y после (а также z) — это разные объекты G>Да, это настолько очевидно что я даже не написал код для проверки
G>
пока не доказано, что сравнение объектов y и y1 имеет хоть какое-нибудь отношение к сравнению объекта y (до) с y (после).
G>Я сделал это на основании того что строки в .NET это reference типы, других соображений не нужно.
правильно я понял, что ты утверждаешь, что всегда когда в коде на c# мы видим операцию = и тип переменной reference, то всегда происходит лишь присваивание ссылки?
G>Хотя сведения о том что += не изменяет строку есть в MSDN, только инкапсуляцию это никак не нарушает.
является ли операция += полиморфной в C#? и если она такой является, то каким контрактом она при этом обладает?
DG>>как ты узнал, что они больше не ссылаются на один и тот же объект? S>ReferenceEquals
не канает.
referenceequals сравнивает ссылки на объекты, что следует из ее названия
а из различности ссылок не следует, что объекты разные.
DG>>через ReferenceEquals? т.е. ты ReferenceEquals используешь и для проверки, что ссылки остались теми же, и для определения идентичности объектов? S>Совершенно верно. Identity is implemented on System.Object via the ReferenceEquals method. (ц)
откуда следует, что данное identity и ООП-identity — это одно и тоже?
DG>>но в определение явно указано, что это две разных функции: функция сравнения ссылок и функция проверки идентичности S>Вообще говоря — это разные функции в широком смысле. Но разве что-то мешает определять одну через другую?
не мешает, но тогда мы получим вырожденый случай ООП, который к самому ООП имеет малое отношение (примерно такое же, какое точка имеет отношение к кругу)
DG>>потому что она нарушает инкапсуляцию объектов. S>А разве есть какая-то связь?
конечно. ООП утверждает, что внешняя сторона имеет право пользоваться только внешним контрактом, и не имеет право лезть в реализацию.
и соотственно, если объект не предоставляет функцию для своего побитового сравнения, то это означает, что с точки зрения ООП ты не имеешь права использовать функцию побитивого сравнения для чего либо.
DG>>>как ты узнал, что они больше не ссылаются на один и тот же объект? S>>ReferenceEquals
DG>не канает. DG>referenceequals сравнивает ссылки на объекты, что следует из ее названия DG>а из различности ссылок не следует, что объекты разные.
Следует по Ecma-335 8.2.5.1
DG>>>через ReferenceEquals? т.е. ты ReferenceEquals используешь и для проверки, что ссылки остались теми же, и для определения идентичности объектов? S>>Совершенно верно. Identity is implemented on System.Object via the ReferenceEquals method. (ц)
DG>откуда следует, что данное identity и ООП-identity — это одно и тоже?
Тогда следует заняться более общими вопросами, например, откуда следует что объекты в C# это ООП-объекты.
DG>>>но в определение явно указано, что это две разных функции: функция сравнения ссылок и функция проверки идентичности S>>Вообще говоря — это разные функции в широком смысле. Но разве что-то мешает определять одну через другую?
DG>не мешает, но тогда мы получим вырожденый случай ООП, который к самому ООП имеет малое отношение (примерно такое же, какое точка имеет отношение к кругу)
А это и есть вырожденный случай ООП. Он, например, имеет мало отношения к вырожденному случаю с COM OOP со своей identity. Правда, у них есть много общего. Например, то, что отношение идентичности в них выполняет условия отношения эквивалентности.
DG>>>потому что она нарушает инкапсуляцию объектов. S>>А разве есть какая-то связь?
DG>конечно. ООП утверждает, что внешняя сторона имеет право пользоваться только внешним контрактом, и не имеет право лезть в реализацию.
Оператор (==) по умолчанию для value типов относится ко внешнему контракту?
DG>и соотственно, если объект не предоставляет функцию для своего побитового сравнения, то это означает, что с точки зрения ООП ты не имеешь права использовать функцию побитивого сравнения для чего либо.
Ну а если для побитового сравнения используется возможность рантайма?
S>Она является функцией идентичности по ECMA для ссылочных типов.
если ReferenceEquals есть та самая Единая функция для проверки идентичности объектов, то почему тогда, например, Dictionary (и Hashtable) ее не использует для проверки объектов на равенство, а использует другую функцию?
Здравствуйте, DarkGray, Вы писали:
S>>Она является функцией идентичности по ECMA для ссылочных типов.
DG>если ReferenceEquals есть та самая Единая функция для проверки идентичности объектов, то почему тогда, например, Dictionary (и Hashtable) ее не использует для проверки объектов на равенство, а использует другую функцию?
Потому что эти классы работают на более общем отношении эквивалентности, чем идентичность.
Здравствуйте, DarkGray, Вы писали:
G>>Я сделал это на основании того что строки в .NET это reference типы, других соображений не нужно.
DG>правильно я понял, что ты утверждаешь, что всегда когда в коде на c# мы видим операцию = и тип переменной reference, то всегда происходит лишь присваивание ссылки?
Кроме тех случаев, когда работают conversion операторы. Но даже тогда, резултатом присваивания будет присваивание ссылки.
G>>Хотя сведения о том что += не изменяет строку есть в MSDN, только инкапсуляцию это никак не нарушает.
DG>является ли операция += полиморфной в C#? и если она такой является, то каким контрактом она при этом обладает?
Полиморфным является (+), а (+=) это лишь сахар, результатом которого будет присваивание левой части результата вызова оператора (+) для левой и правой частей выражения.
Раз (+) для строк не изменяет состояние строки, то и (+=) не будет. Если бы (+) для строки изменял состояние строки, то изменял бы ее состояние именно он, а не последующий (=), который бы лишь присваивал ссылку.
DG>>конечно. ООП утверждает, что внешняя сторона имеет право пользоваться только внешним контрактом, и не имеет право лезть в реализацию. S>Оператор (==) по умолчанию для value типов относится ко внешнему контракту?
согласен на такое допущение
при этом ты утверждаешь, что оператор == для value-типов в .net сравнивает побитово?
DG>>если ReferenceEquals есть та самая Единая функция для проверки идентичности объектов, то почему тогда, например, Dictionary (и Hashtable) ее не использует для проверки объектов на равенство, а использует другую функцию? S>Потому что эти классы работают на более общем отношении эквивалентности, чем идентичность.
DG>>откуда следует, что данное identity и ООП-identity — это одно и тоже? S>Тогда следует заняться более общими вопросами, например, откуда следует что объекты в C# это ООП-объекты.
DG>>>конечно. ООП утверждает, что внешняя сторона имеет право пользоваться только внешним контрактом, и не имеет право лезть в реализацию. S>>Оператор (==) по умолчанию для value типов относится ко внешнему контракту?
DG>согласен на такое допущение
DG>при этом ты утверждаешь, что оператор == для value-типов в .net сравнивает побитово?
хм, для predefined — да. Для остальных — неопределен.
DG>>>если ReferenceEquals есть та самая Единая функция для проверки идентичности объектов, то почему тогда, например, Dictionary (и Hashtable) ее не использует для проверки объектов на равенство, а использует другую функцию? S>>Потому что эти классы работают на более общем отношении эквивалентности, чем идентичность.
DG>и в рамках какой модели это происходит?
В рамках указанного бинарного отношения эквивалентности на множестве значений ключа.
DG>>>откуда следует, что данное identity и ООП-identity — это одно и тоже? S>>Тогда следует заняться более общими вопросами, например, откуда следует что объекты в C# это ООП-объекты.
DG>а мы здесь чем занимаемся?
Путаем объекты с переменными и пытаемся понять, почему это не хорошо.
DG>>>при этом ты утверждаешь, что оператор == для value-типов в .net сравнивает побитово? S>>хм, для predefined — да.
DG>нет, же. конечно. DG>вот тебе два контрпримера. в одном случае битовое представление одинаковое, но == возвращает false. DG>в другом случае — обратное. битовое представление различное, но сравнение одинаковое.
Да, ты прав. (==) не сравнивает побитово. Но с выводами из этого согласиться не могу.
DG>>>а мы здесь чем занимаемся? S>>Путаем объекты с переменными и пытаемся понять, почему это не хорошо.
DG>в ООП нет переменных, поэтому не понятно что с чем путаем
Вот мне тоже не понятно, но есть ощущение, что ты называешь объектом не объект, а то ли переменную, то ли ссылку на объект. С чего у тебя += для строк якобы изменяет объект?
DG>>>и в рамках какой модели это происходит? S>>В рамках указанного бинарного отношения эквивалентности на множестве значений ключа.
DG>а модель где? DG>hint: в модели должны вводится какие-то понятия, допущения, делаться какие-то следствия и выводы.
Я не понимаю, о чем речь. Какие допущения и следствия нужны для работы словаря, кроме свойств отношения эквивалентности, ну и GetHashCode(), соответственно?
DG>>а модель где? DG>>hint: в модели должны вводится какие-то понятия, допущения, делаться какие-то следствия и выводы. S>Я не понимаю, о чем речь. Какие допущения и следствия нужны для работы словаря, кроме свойств отношения эквивалентности, ну и GetHashCode(), соответственно?
тогда попробуй сначала ответить на вопрос:
как мы видели даже у predefined-типов изменен оператор == как минимум для типов:
double, decimal и string — он возвращает не тоже самое, что описано в Ecma Identity.
зачем это было сделано?
Здравствуйте, DarkGray, Вы писали:
DG>>>а модель где? DG>>>hint: в модели должны вводится какие-то понятия, допущения, делаться какие-то следствия и выводы. S>>Я не понимаю, о чем речь. Какие допущения и следствия нужны для работы словаря, кроме свойств отношения эквивалентности, ну и GetHashCode(), соответственно?
DG>тогда попробуй сначала ответить на вопрос: DG>как мы видели даже у predefined-типов изменен оператор == как минимум для типов: DG>double, decimal и string — он возвращает не тоже самое, что описано в Ecma Identity. DG>зачем это было сделано?
Вообще говоря, никто не настаивал на том что оператор (==) должен возвращать то, что описано в Ecma Identity. Оператор (==) определяет эквивалентность, а не идентичность.
DG>>в ООП нет переменных, поэтому не понятно что с чем путаем S>Вот мне тоже не понятно, но есть ощущение, что ты называешь объектом не объект, а то ли переменную, то ли ссылку на объект. С чего у тебя += для строк якобы изменяет объект?
потому что с точки зрения ООП для выдвижение тех или иных утверждений я должен пользоваться только внешним контрактом, и только теми понятиями, которые есть в ООП.
в ООП есть понятие объект, косвенно упоминается понятие ссылка, понятия переменной там нет.
соответственно, когда я вижу код:
x += "1";
и для описания использую вышепревиденные понятия, то у меня получается следующее:
x — это ссылка, потому что обладает ссылочным контрактом (объект, конечно, тоже — потому что в ООП: всё есть объект)
+= dx — это полиморфная операция обладающая контрактом: изменение объекта на величину dx (и этим она отличается от операции +, у которой в контракте зафиксировано, что она создает новый объект)
используя оба эти утверждения, я получаю, что после применения этого кода я получаю через x тот же самый объект, но измененный на величину dx
при этом с помощью функции referenceequals я могу сравнить ссылки на этот объект с чем-нибудь, а с помощью equals(или ==) сравнить состояние этого объекта с чем-нибудь.
вы же утверждаете, что всё это не так, при этом ссылаясь на детали реализации, хотя ООП утверждает, что как раз детали реализации могут быть любыми — важен лишь контракт.
S>Вообще говоря, никто не настаивал на том что оператор (==) должен возвращать то, что описано в Ecma Identity. Оператор (==) определяет эквивалентность, а не идентичность.
на секунду допустим этого.
тогда вопрос: при этом equality может ли быть различным, если идентичность одна и та же?
DG>>>в ООП нет переменных, поэтому не понятно что с чем путаем S>>Вот мне тоже не понятно, но есть ощущение, что ты называешь объектом не объект, а то ли переменную, то ли ссылку на объект. С чего у тебя += для строк якобы изменяет объект?
DG>потому что с точки зрения ООП для выдвижение тех или иных утверждений я должен пользоваться только внешним контрактом, и только теми понятиями, которые есть в ООП. DG>в ООП есть понятие объект, косвенно упоминается понятие ссылка, понятия переменной там нет.
DG>соответственно, когда я вижу код: DG>x += "1"; DG>и для описания использую вышепревиденные понятия, то у меня получается следующее: DG>x — это ссылка, потому что обладает ссылочным контрактом (объект, конечно, тоже — потому что в ООП: всё есть объект)
Все есть объект — это не про понятия ЯВУ. Это про моделирование.
DG>+= dx — это полиморфная операция обладающая контрактом: изменение объекта на величину dx
А откуда ты взял что это изменение объекта? DG>(и этим она отличается от операции +, у которой в контракте зафиксировано, что она создает новый объект)
В C# += это сахар для + с последующим присваиванием.
DG>используя оба эти утверждения, я получаю, что после применения этого кода я получаю через x тот же самый объект, но измененный на величину dx
Вот по поводу того же самого — явно не так.
DG>при этом с помощью функции referenceequals я могу сравнить ссылки на этот объект с чем-нибудь, а с помощью equals(или ==) сравнить состояние этого объекта с чем-нибудь.
Вот сравни ссылки, и пойми, что ты получил не изменение объекта, а новый объект.
DG>вы же утверждаете, что всё это не так, при этом ссылаясь на детали реализации, хотя ООП утверждает, что как раз детали реализации могут быть любыми — важен лишь контракт.
контракт в данном случае следующий
x = operator(+)(x, dx)
S>>Вообще говоря, никто не настаивал на том что оператор (==) должен возвращать то, что описано в Ecma Identity. Оператор (==) определяет эквивалентность, а не идентичность.
DG>на секунду допустим этого. DG>тогда вопрос: при этом equality может ли быть различным, если идентичность одна и та же?
Такая реализация возможна, но надо понимать, что она не будет удовлетворять требованиям отношения эквивалентности. Не будет выполняться рефлексивность.
DG>>соответственно, когда я вижу код: DG>>x += "1"; DG>>и для описания использую вышепревиденные понятия, то у меня получается следующее: DG>>x — это ссылка, потому что обладает ссылочным контрактом (объект, конечно, тоже — потому что в ООП: всё есть объект) S>Все есть объект — это не про понятия ЯВУ. Это про моделирование.
бездоказательно.
DG>>+= dx — это полиморфная операция обладающая контрактом: изменение объекта на величину dx S>А откуда ты взял что это изменение объекта? DG>>(и этим она отличается от операции +, у которой в контракте зафиксировано, что она создает новый объект) S>В C# += это сахар для + с последующим присваиванием.
согласен. был не прав, использовал контракт для += из C++.
DG>>при этом с помощью функции referenceequals я могу сравнить ссылки на этот объект с чем-нибудь, а с помощью equals(или ==) сравнить состояние этого объекта с чем-нибудь. S>Вот сравни ссылки, и пойми, что ты получил не изменение объекта, а новый объект.
я уже давал ссылку на определение, в котором явно сказано, что разницы ссылок не следует, что объект не тот же самый
Здравствуйте, DarkGray, Вы писали:
S>>Она является функцией идентичности по ECMA для ссылочных типов.
DG>если ReferenceEquals есть та самая Единая функция для проверки идентичности объектов, то почему тогда, например, Dictionary (и Hashtable) ее не использует для проверки объектов на равенство, а использует другую функцию?
Потому что для Dictionary (и Hashtable) нужна не идентичность, а эквивалентность. Идентичность является одним из вариантов эквивалентности, только вот идентичность по разному определяется для ref и value типов.
Вообще-то в Ecma-335 вполне точно описано что есть идентичность, чем она отличается от эквивалентности и для чего они нужны.
S>>Вообще говоря, никто не настаивал на том что оператор (==) должен возвращать то, что описано в Ecma Identity. Оператор (==) определяет эквивалентность, а не идентичность.
DG>на секунду допустим этого. DG>тогда вопрос: при этом equality может ли быть различным, если идентичность одна и та же?
Вполне. Читай ecma-335, там черным по английскому написано математическое определение equality: бинарное отношение обладающее свойствами рефлексивности, симметричности, транзитивности.
identity частный случай отношения equality и в ООП требуется чтобы объект был идентичен только сам себе и это отношение не зависело от состояния и поведения. В ecma-335 identity определен как ReferenceEquals и состоявшиеся дебаты на форуме показали что другой реализации identity в рамках ecma нету.
DG>>>твое "ну, понял" справедливо только при следующих утверждениях: DG>>>1) y1 и y (а также z1 и z) — это один и тот же объект G>>Присваивание ссылок очевидно сохраняет identity.
DG>как только появляется слово "очевидно", то это означает, что человек не может объяснить происходящее.
Ты не понимаешь почему присваивангие ссылок не меняет identity? Тогда вопрос как мы работаем с объектами в программе? Что мы используем чтобы обратиться к объекту? Видимо ссылку.
Так вот с точки зрения ООП есть функция identity, которая принимает две ссылки и говорит true если они обе ссылаются на один объект и false в противном случае.
DG>откуда известно, что в данном месте происходит присвоение ссылок, а не что-то другое?
Из ecma-335, так как для ref-типов оператор "=" — присвоение ссылок. Мы ведь в рамках ecma-335 находимся, не так ли?
G>>Я сделал это на основании того что строки в .NET это reference типы, других соображений не нужно.
DG>правильно я понял, что ты утверждаешь, что всегда когда в коде на c# мы видим операцию = и тип переменной reference, то всегда происходит лишь присваивание ссылки?
Именно так.
G>>Хотя сведения о том что += не изменяет строку есть в MSDN, только инкапсуляцию это никак не нарушает.
DG>является ли операция += полиморфной в C#? и если она такой является, то каким контрактом она при этом обладает?
a+=b является "сахаром" для a=a+b, это уже по ecma-334.
DG>>правильно я понял, что ты утверждаешь, что всегда когда в коде на c# мы видим операцию = и тип переменной reference, то всегда происходит лишь присваивание ссылки? G>Именно так.
а вот samius смог вовремя распознать подвох.
поэтому я еще раз повторю, что как только человек говорит "очевидно", это означает что человек не понимает то, о чем говорит.
DG>>откуда известно, что в данном месте происходит присвоение ссылок, а не что-то другое? G>Из ecma-335, так как для ref-типов оператор "=" — присвоение ссылок. Мы ведь в рамках ecma-335 находимся, не так ли?
DG>правильно я понял, что ты утверждаешь, что всегда когда в коде на c# мы видим операцию = и тип переменной reference, то всегда происходит лишь присваивание ссылки?
Именно так.
[занудно]
из того, что для ref-типов оператор '=' используется для присвоение ссылок не следует, что каждое использование оператор '=' для ref-типов является лишь присвоением ссылок.
DG>>если ReferenceEquals есть та самая Единая функция для проверки идентичности объектов, то почему тогда, например, Dictionary (и Hashtable) ее не использует для проверки объектов на равенство, а использует другую функцию? S>Потому что эти классы работают на более общем отношении эквивалентности, чем идентичность.
я правильно понимаю, что фактически под идентичностью вы понимаете возможность определения, что объект является сам собой же?
для каких алгоритмов (ситуаций, задач и т.д.) это знание вообще требуется?
Здравствуйте, vdimas, Вы писали:
V>Да, но не заданы свыше. Это принципиально.
А про "свыше" никто и не говорит. Вот сели разработчики дотнета, и безо всякой подсказки свыше разделили слои C#, СLR и так далее.
V>Ну таки при некотором навыке экономит невообразимую массу времени во время разработки. И во время поиска узких мест у коллег тоже. Там не rocket-science вовсе... ты же обратил внимание, что мне сам факт обсуждения подобных вещей кажется странным?
Обратил. Это как раз признак догматического мышления
V>Скажу так, что ПЕРЕД началом оптимизаций, программу необходимо переписать.
Хм. Я-то ожидал 100% предсказания результатов профайлера. Ну уж если не прямо процентовки времени вызовов, то хотя бы порядок, в котором в выходе профайлера будут идти функции. Ну да ладно, замнём. Мне важно было понять, что вы считаете заменой профайлеру.
V>Это можно в тестах выяснить, зачем что читать? Как раз тонкости реализаций не всегда описаны. Берем 2 независимые от вызовов операции, одинаковые по стоимости в случае одного потока. Затем прогоняем их на многопроцессорной машине из многих потоков, строим график и видим, какая операция масштабируется фактически линейно, а какая нет.
Ну, тут многое может зависеть от деталей организации теста. Ок, при случае проверю ваши предположения.
Но, тут важно вот что: не слеплять в голове понятия "мьютекс" и "делегат" в одно понятие. Потому, что когда в версии фреймворка N+1 реализацию изменят, ваши интуитивные представления о том, что медленно, а что быстро, окажутся неверными.
V>А ты понял значение этих терминов? Bookmark Lookup — это восстановление соответствия м/у выделенным индексом и индексируемыми строками.
Я-то понял. Вы лучше откройте-ка учебник по реляционной алгебре, и попробуйте найти в нём операцию "восстановление соответствия м/у выделенным индексом и индексируемыми строками." V>Откуда берутся индексы — уже говорил выше. Clustered Index Seek — это есть операция "выборка" по проекции или "ограничение".
"Clustered" — это подробность хранения индекса, идет из раздела реляционных баз данных. Я уже упоминал, что реляционные базы, реляционная модель, реляционное исчисление и реляционная алгебра связаны друг с другом. Матаппарат делиться на разделы, ок, ну разделы и разделы себе... Но использовать одно без другого бессмысленно, ведь реляционная модель была придумана для реляционных баз, а реляционное исчисление и реляционная алгебра были введены как инструмент над реляционной моделью. А вовсе не "сами по себе".
Они, конечно же, не сами по себе. Тем не менее, в РА нет и не может быть никаких индексов. Потому что индексы определяются в терминах подробностей хранения данных, а их в РА нету.
V>Таки настаиваю. Понимаешь, индекс можно построить даже по данным, которые не поддерживают операцию сравнения, хоть этого нельзя конкретно в MS SQL, но это лишь подробности MS SQL. Принципиально в таком индексе будет то, что объем данных проекции может быть гораздо меньше объема всех данных, поэтому операция выборки/ограничения по индексу может быть выполнена многократно эффективнее, чем по всем исходным данным. Вот так может приниматься решение — делать индекс кластерным или некластерным.
Вы напрасно спорите с очевидным. Если мы рассуждаем исключительно в терминах РА, то нет никакого смысла в "сохранении" результата какой-то операции, т.к. там нет понятия "эффективности". Если мы рассуждаем в терминах RDBMS, то операции "проекция" недостаточно, по двум причинам:
1. Индекс, помимо "публичных" данных, которые можно получить в результате проекции, хранит обратные ссылки на "строки таблицы". В РА невозможно сослаться на конкретную строку.
2. Индекс, помимо "содержания" данных, обладает особенностями их размещения, которые позволяют некоторые операции выполнять быстрее. В частности, поиск значения ключа в индексе традиционно выполняется за O(log(N)) либо O(N/M), с достаточно большими основаниями логарифма или M для того, чтобы в практических случаях это сводилось к O(1). Некоторые виды индексов также позволяют делать c подобной асимптотикой операции диапазонного поиска.
Кстати, индекс для данных, не поддерживающих операции сравнения, не имеет никакого смысла.
V>Еще раз большими буквами — любой некластерный индекс — это и есть проекция. В классике индексы некластерные изначально. Просто в MS SQL ввиду особенностей хранения блобов кластерные индексы оч популярны.
Вы продолжаете писать бессмысленный набор слов. Популярность кластерных индексов в MS SQL никак не связана с особенностями хранения блобов, да и вообще с блобами не связана. Я написал определение некластерного индекса — попробуйте соорудить проекцию(т.е. таблицу), которая будет эквивалентна ему по производительности.
V>Я тебе скажу так, в достаточно большой системе, с многими миллионами записей движений и сотнеями справочников, одно лишь только изменение суррогатных ключей с типа int на shortint в справочниках и оформление индексов как некластерных у справочников, где записи достаточно большие (много полей) подняло производительность более чем в четверо. Вот зачем нужна проекция при построении индекса — это снижение объема перелопачиваемых данных при операциях над таблицами, проводимыми по этому индексу/ключу (фактически все операции из РА).
Я вас разочарую: снижение объема перелопачиваемых данных в индексах выполняется не за счёт операций проекции, а за счёт организации данных.
V>Наверно не понимаешь, что есть реляционное исчисление, а что есть реляционная алгебра, так? Это совсем не одно и то же.
И тем не менее, SQL не оперирует понятиями реляционной модели.
V>Я не знаю, что есть логическое, а что есть физическое в твоем понимании?
Это я вижу. Поясняю: При рассмотрении анатомии оптимизаторов запросов в СУБД, выделяют два вида "планов запроса":
1. Логический план. Выражается в терминах операций расширенной РА; является результатом синтаксического разбора SQL запроса и некоторой предварительной оптимизации. Предварительные оптимизации на этом этапе имеют целью упрощение плана для дальнейшего анализа и устранение заведомых неоптимальностей.
2. Физический план. Выражается в терминах императивных операций, работающих над конкретными объектами реляционной базы. Это совсем другие операции. Скажем, там, где в логическом плане была пара операций π и σ, в физическом плане будет одна операция table scan. Или одна операция index seek. Или операция index scan и операция bookmark lookup.
V>Использование разного порядка сканирования индексов — это физическое отличие или логическое?
Конечно же это отличие физического плана. В логическом плане никаких индексов нет. V>А ведь разные вещи, хотя с т.з. реляционного исчисления — это не имеет значения, но с т.з. реляционной алгебры — это разная последовательность императивных операций над разными таблицами-индексами.
В реляционной алгебре нет никаких императивных операций. RTFM.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>>откуда известно, что в данном месте происходит присвоение ссылок, а не что-то другое? G>>Из ecma-335, так как для ref-типов оператор "=" — присвоение ссылок. Мы ведь в рамках ecma-335 находимся, не так ли?
DG>>правильно я понял, что ты утверждаешь, что всегда когда в коде на c# мы видим операцию = и тип переменной reference, то всегда происходит лишь присваивание ссылки? DG>Именно так.
DG>[занудно] DG>из того, что для ref-типов оператор '=' используется для присвоение ссылок не следует, что каждое использование оператор '=' для ref-типов является лишь присвоением ссылок.
И? Что ты хочешь сказать? Главный вопрос меняется ли identity при присвоении ссылок? Ответ — нет. Остальное нерелевантно обсуждению.
А вообще приводи ссылки на ecma когда пишешь свои опусы.
DG>>>если ReferenceEquals есть та самая Единая функция для проверки идентичности объектов, то почему тогда, например, Dictionary (и Hashtable) ее не использует для проверки объектов на равенство, а использует другую функцию? S>>Потому что эти классы работают на более общем отношении эквивалентности, чем идентичность.
DG>я правильно понимаю, что фактически под идентичностью вы понимаете возможность определения, что объект является сам собой же?
Именно так. Причем отношение индентичности не должно опираться на состояние и поведение.
DG>для каких алгоритмов (ситуаций, задач и т.д.) это знание вообще требуется?
Это требуется в первую очередь для ООП. Читай кея.
Хочешь конкретный пример — Dictionary с mutable ключом.
Здравствуйте, Sinclair, Вы писали:
V>>Скажу так, что ПЕРЕД началом оптимизаций, программу необходимо переписать. S>Хм. Я-то ожидал 100% предсказания результатов профайлера. Ну уж если не прямо процентовки времени вызовов, то хотя бы порядок, в котором в выходе профайлера будут идти функции. Ну да ладно, замнём. Мне важно было понять, что вы считаете заменой профайлеру.
Повторю, профайлер врет, когда подходим уже к шлифовке кода, поэтому нужен лишь для того, чтобы составить общую картинку о происходящем, расставиьт приоритет при составлении плана итераций оптимизации (для примера, при работе над последним продуктом вышло 4 итерации оптимизаций). По крайней мере, когда речь идет об увеличении производительности на порядок, причем, не за счет замены алгоритмов в терминах O(n), а сугубо за счет технических деталей, т.е. когда речь идет лишь о коэф К при O(n), профайлер уже не так хорош и даже вреден. Так вот, в смысле обнаружения узких мест опытный взгляд ловит те самые места и так. Я имел ввиду 100% совпадения относительно самих этих узких мест. Разумеется, реальная картинка в каждом случае может быть выяснена лишь в тестах на производительность, другого адекватного пути нет.
Конкретно твой пример я даже толком не смотрел, тем более не компилировал и не запускал под профайлером. Просто загорелась "красная лампочка" на "стандартной" ситуации с рекурсивным созданием энумераторов, я вернулся чуть выше и грубо оценил, от чего зависит глубина рекурсии (единственное во что вник в том коде), ну и в следующем методе увидел открытие файла, разумеетсятут же проверил откуда это вызвано, и тут же увидел, что открытие в цикле с последующим линейным (!!!) сканированием результата. Кстати, на следующей итерации оптимизаций, я бы снипет кода, который предложил добавить для сортировки слов по длине, перенес бы в утилиту формирования этого файла данных.
S>Но, тут важно вот что: не слеплять в голове понятия "мьютекс" и "делегат" в одно понятие. Потому, что когда в версии фреймворка N+1 реализацию изменят, ваши интуитивные представления о том, что медленно, а что быстро, окажутся неверными.
Не спорю, но конкретный продукт обычно выкатывается под конкретный фрейморк, который указан в официальных требованиях продукта. На самом деле это всего лишь один из моментов, как пример. И да, разумеется, совсем от делегатов никто не отказывается, мы же не идиоты, ведь шла о нагрузочном сценарии создания их в цикле, который может быть вызван в многопоточном сценарии, т.е. когда другой кто-то конкурирует за ту же операцию с делегатами. Как с этим всем бороться — вроде и так понятно, оно на поверхности — не создавать их внутри нагрузочных сценариев, а подготавливать экземпляры делегатов "заранее". Это именно то, что я имел ввиду, говоря что не надо никакого rocket science, достаточно лишь чуток здравого смысла и немного ответственности за свой код.
V>>А ты понял значение этих терминов? Bookmark Lookup — это восстановление соответствия м/у выделенным индексом и индексируемыми строками. S>Я-то понял. Вы лучше откройте-ка учебник по реляционной алгебре, и попробуйте найти в нём операцию "восстановление соответствия м/у выделенным индексом и индексируемыми строками."
Реляционная алгебра оперирует понятием "кортеж однозначно определяется ...", посмотри задачки по реляционной алгебре: аттрибуты, однозначно определяющие кортеж, дополняют символом '#' в их названиях. Выделение индекса расписывают как декомпозицию отношения с вводом нового такого аттрибута с символом '#' в обоих отношениях. Можешь такой аттрибут для удобства понимания считать за кластерный индекс.
S>Они, конечно же, не сами по себе. Тем не менее, в РА нет и не может быть никаких индексов. Потому что индексы определяются в терминах подробностей хранения данных, а их в РА нету.
Еще раз, не существует РА в вакууме, это инструмент над реляционной моделью, которая оперирует отношениями, зависимостями и ограничениями целостности. Да, ограничения целостности делаются на индексах в реальности, а отношения представляют в виде таблиц..... Однако, у тебя же не вызывает сложности использования термина "таблица"? Почему с "индексом" проблемы?.. Ну и таки стоит прочесть работу, в которой Кодд ввел само понятие реляционной модели, реляционной алгебры и реляционного исчисления. Он про индексы говорит уже в первых главах. Наверно поэтому я никогда не пытался отделять одно от другого, что это преподают совместно: реляционную модель данных, РА, реляционное исчисление и реляционные СУБД с их нормальными формами. Это общий курс изучения, где на каждый из разделов по паре лекций. Ты мне предлагаешь эту каждую лекцию ни в коем случае "не смешивать" с остальными? Это можно делать только не понимая взаимосвязи разделов внутри области "реляционные СУБД", ведь каждая из них не живет сама по себе, а оперирует понятиями смежных областей.
DG>>>соответственно, когда я вижу код: DG>>>x += "1"; DG>>>и для описания использую вышепревиденные понятия, то у меня получается следующее: DG>>>x — это ссылка, потому что обладает ссылочным контрактом (объект, конечно, тоже — потому что в ООП: всё есть объект) S>>Все есть объект — это не про понятия ЯВУ. Это про моделирование.
DG>бездоказательно.
DG>>>+= dx — это полиморфная операция обладающая контрактом: изменение объекта на величину dx S>>А откуда ты взял что это изменение объекта? DG>>>(и этим она отличается от операции +, у которой в контракте зафиксировано, что она создает новый объект) S>>В C# += это сахар для + с последующим присваиванием.
DG>согласен. был не прав, использовал контракт для += из C++.
DG>>>при этом с помощью функции referenceequals я могу сравнить ссылки на этот объект с чем-нибудь, а с помощью equals(или ==) сравнить состояние этого объекта с чем-нибудь. S>>Вот сравни ссылки, и пойми, что ты получил не изменение объекта, а новый объект.
DG>я уже давал ссылку на определение, в котором явно сказано, что разницы ссылок не следует, что объект не тот же самый
Я давал ссылку на ECMA, из которой ясно что из разницы ссылок следует что объект не тот же самый. Мы о дотнете, или о сферической ОО системе?
DG>>>если ReferenceEquals есть та самая Единая функция для проверки идентичности объектов, то почему тогда, например, Dictionary (и Hashtable) ее не использует для проверки объектов на равенство, а использует другую функцию? S>>Потому что эти классы работают на более общем отношении эквивалентности, чем идентичность.
DG>я правильно понимаю, что фактически под идентичностью вы понимаете возможность определения, что объект является сам собой же?
Нет, идентичность — это то что отличает объект от других объектов. Сама возможность определять где один объект, а где другой нужна далеко не всем программам. Если вспомнить о примере str+="dx", то возможность определять, остался ли объект сам собой, дает нам возможность разобраться в происходящем, а после мы можем написать программу без использования ReferenceEquals.
DG>для каких алгоритмов (ситуаций, задач и т.д.) это знание вообще требуется?
Умение отличать объекты — да оно не особо и требуется для программы. А вот понимание, где один объект, где другой, какому из них послалось сообщение, какой из них изменил состояние, какой породил новый и т.п. — это важно.
DG>>для каких алгоритмов (ситуаций, задач и т.д.) это знание вообще требуется? S>Умение отличать объекты — да оно не особо и требуется для программы. А вот понимание, где один объект, где другой, какому из них послалось сообщение, какой из них изменил состояние, какой породил новый и т.п. — это важно.
можно ли это сформулировать как:
в некоторых сценариях требуется понимать: где начинается один объект, заканчивается другой, и какой объект кому послал сообщение?
G>>Хочешь конкретный пример — Dictionary с mutable ключом.
DG>и что здесь не так? проблема имеет даже лобовое решение, сделать чтобы dictionary подписывался на изменение ключа
Это как минимум потребует ручного определения equals для каждого класса и реализацию INotifyPropertyChanged.
И это только один пример, таким можно тысячи придумать.
S>Я давал ссылку на ECMA, из которой ясно что из разницы ссылок следует что объект не тот же самый. Мы о дотнете, или о сферической ОО системе?
я о реальной ОО-системе, в которой есть .net, база, remoting (тот, или иной), клиентский javascript и т.д.
и в целом, для такой системы — по барабану, что там написано в ecma, потому что это никак не помогает ответить на вопрос, что есть объект, когда он размазан по трем серверам, баре базе и тысяче клиентов.
и уж точно для сравнения таких объектов будет использовать не referenceequals.
Здравствуйте, DarkGray, Вы писали:
S>>Я давал ссылку на ECMA, из которой ясно что из разницы ссылок следует что объект не тот же самый. Мы о дотнете, или о сферической ОО системе?
DG>я о реальной ОО-системе, в которой есть .net, база, remoting (тот, или иной), клиентский javascript и т.д. DG>и в целом, для такой системы — по барабану, что там написано в ecma, потому что это никак не помогает ответить на вопрос, что есть объект, когда он размазан по трем серверам, баре базе и тысяче клиентов. DG>и уж точно для сравнения таких объектов будет использовать не referenceequals.
Вопрос, что же делает такую реальную систему ОО-системой? Может быть то, что она собрана из объектов ECMA-ОО-системы, а не то, что мы не можем ответить на вопрос, что есть объект, когда он размазан по трем серверам, базе и тысяче клиентов? И уж совершенно очевидно что referenceequals не сможет ответить на вопрос, что есть объект, т.к. в "реальной ОО-системе" даже авторы не могут ответить на вопрос, что есть объект. Вроде как от ECMA идентити ушли, а к своей не пришли. Так вот, согласно ECMA, эта реальная identity будет всего лишь эквивалентностью, и то лишь при условии выполнения ряда условий из определения эквивалентности.
Ничего общего у реальной айдентити с ОО-айдентити наблюдаться не может. Вот послал я объекту сообщение, изменяющее состояние, а почему-то объект с той же "реальной" identity на тысяче остальных клиентов, на это не среагировал. Ну и причем тут ООП?
S> Так вот, согласно ECMA, эта реальная identity будет всего лишь эквивалентностью, и то лишь при условии выполнения ряда условий из определения эквивалентности.
и фиг с ним. в каких сценариях это будет аукаться?
мы вон уже выяснили, что даже double полностью не поддерживает идентичность (рефлексивность сооблюдается только на подмножестве всех значений)
и когда это последний раз аукалось? и в каких сценариях нельзя рассматривать double (переменную типа double) как объект?
или возьмем реальный пример: версионный объект (двух типов). версионный объект при определенных изменениях создает версии своего состояния.
объект с версионностью первого типа: создает версию, если явно его об это попросить
var xv = x.FixVersion();
var y = x;
y.Change1();
во втором сценарии, версия объекта создается автоматически при изменении объекта
var y = x.Change1();
в обоих этих сценариях появляется две плоскости:
ecma-объекты и логические объекты. (и те и другие удовлетворяют ОО-модели).
что здесь является функцией идентичности для логических объектов?
кстати, эти обе версионности являются эквивалентными: через адаптер можно одну версионность преобразовать к второй версионности, и наоборот.
первый вариант версионности назовем backup-версионность
второй вариант версионности назовем immutable-версионность
immutable-версионность обладает интересным свойством: ссылка x всегда ссылается на ту версию объекта, которой была проинициализирована, вне зависимости от того, в какой момент времени был произведен реальный вызов.
и оказывается, что для сложного кода со сложными оптимизациями (lazy, создание по требованию и т.д.) удобнее работать с объектами с immutable-версионностью: потому что при lazy есть состояние неопределенности, когда произойдет реальный вызов, а immutable-версионность гарантирует, что даже несмотря на эту неопределенность поведение всегда будет одним и тем же.
соответственно, подбирая под каждую неопределенность объекты с определенным поведением(контрактом) можно последовательно сделать так, чтобы неопределенности не мешали выдавать определенное поведение.
S> Вот послал я объекту сообщение, изменяющее состояние, а почему-то объект с той же "реальной" identity на тысяче остальных клиентов, на это не среагировал. Ну и причем тут ООП?
отличное ООП, просто в контракте на такое сообщение написано, что сообщение может не дойти.
и отдельно оговаривается, что происходит если не дошел запрос к объекту, и отдельно, если не дошел ответ от объекта.
и при этом простую ООП-архитектуру можно строить даже поверх таких особенностей(ограничений).
тут, кстати, опять же помогают объекты с версионностью второго типа, когда мы четко знаем, какая ссылка на какую версию объекта ссылается. для таких объектов код для разрешения потери сообщения через несколько повторов сообщения пишется элементарно (делаем допущение, что потеря сообщения формирует исключение, в том числе и через клентский-timeout, если ответ не пришел через заданное время):
var y = x.Try(3, _=>_.Change1());
static T Try<T>(this T x, int count, Func<T, T> action)
{
for (int i = 0; i < count; ++i)
{
try
{
return Action(x);
}
catch (Exception exc)
{
if (i == count - 1)
throw;
}
}
throw new ArgumentException("count");
}
для объектов без версионности, или с backup-версионностью — рассмотрение всех вариантов (сообщение не дошло; сообщение дошло, но объект отказался его обрабатывать(вернул исключение); не дошел ответ и т.д.) и написание кода для корректной обработки всех вариантов — это очень сложная задача, чем обычно и пренебрегают, что видно на реальных программах.
Здравствуйте, DarkGray, Вы писали:
S>> Так вот, согласно ECMA, эта реальная identity будет всего лишь эквивалентностью, и то лишь при условии выполнения ряда условий из определения эквивалентности.
DG>и фиг с ним. в каких сценариях это будет аукаться?
Ты уже подменяешь тему разговора. Ведь изначально ты говорил о том что ReferenceEquals не является индентичностью в CLR. Но со спекой спорить бесполезно, теперь ты пытаешься выдумать свою ОО-систему, для которой выдумываешь идентичность, не совпадающую с ООП-идентичностью.
DG>мы вон уже выяснили, что даже double полностью не поддерживает идентичность (рефлексивность сооблюдается только на подмножестве всех значений) DG>и когда это последний раз аукалось? и в каких сценариях нельзя рассматривать double (переменную типа double) как объект?
В любых. Все value-типы не являются объектами в смысле ООП
DG>или возьмем реальный пример: версионный объект (двух типов). версионный объект при определенных изменениях создает версии своего состояния.
DG>объект с версионностью первого типа: создает версию, если явно его об это попросить DG>
DG>var xv = x.FixVersion();
DG>var y = x;
DG>y.Change1();
DG>
DG>во втором сценарии, версия объекта создается автоматически при изменении объекта DG>
DG>var y = x.Change1();
DG>
DG>в обоих этих сценариях появляется две плоскости: DG>ecma-объекты и логические объекты. (и те и другие удовлетворяют ОО-модели).
Вторые не удовлетворяют. Для объектов в ООП нужно: а) отношение идентичности б)если А иднетичен Б, то любое изменение А сразу отражается на Б. Это и есть определение ОО-идентичности. Вообще говоря идентичность в не-ОО среде является одним из отношений эквивалентности.
DG>immutable-версионность обладает интересным свойством: ссылка x всегда ссылается на ту версию объекта, которой была проинициализирована, вне зависимости от того, в какой момент времени был произведен реальный вызов.
Ты удивишься, но для immutable идентичность не нужна,она полностью изоморфна эквивалентности. В этом плане кстати ФП, которое опирается на immutable, не является в полной мере ОО. Но это уже философия.
S>> Вот послал я объекту сообщение, изменяющее состояние, а почему-то объект с той же "реальной" identity на тысяче остальных клиентов, на это не среагировал. Ну и причем тут ООП?
DG>отличное ООП, просто в контракте на такое сообщение написано, что сообщение может не дойти. DG>и отдельно оговаривается, что происходит если не дошел запрос к объекту, и отдельно, если не дошел ответ от объекта. DG>и при этом простую ООП-архитектуру можно строить даже поверх таких особенностей(ограничений).
Тут другой вопрос. Основное свойство identity: если А иднетичен Б, то любое изменение А сразу отражается на Б. В распределенной среде ты не сможешь этого гарантировать. Смотри CAP-теорему.
Если же рассматривать только immutable, то оно не является в полной мере ОО-системой.
Здравствуйте, Sinclair, Вы писали:
S>Я-то понял. Вы лучше откройте-ка учебник по реляционной алгебре, и попробуйте найти в нём операцию "восстановление соответствия м/у выделенным индексом и индексируемыми строками."
Кстати, прочел еще раз... выделенное любопытно. А что за учебник-то? В любом учебнике по реляционным СУБД предмету РА посвящается одна (практически самая маленькая) глава. А если ты пройдешься по задачам или обсуждениям по этой теме, то увидишь, что когда речь идет о РА, всегда подразумевают так же низлежащую реляционную модель, а задания по РА почти всегда идут в виде реляционного исчисления.
Сдается мне, что из плоскости обсуждения абстракций мы незаметно перескочили в плоскость обсуждения фундаментных наук vs прикладных. А там ведь обсуждать нечего. Фундаментальные науки от прикладных отличаются лишь универсальностью и более ничем. Например, теория матриц — раздел фундаментальной науки, и я могу навскидку назвать более десятка ее несвязанных приложений. В то время как законы Ома не живут вне Теории цепей, т.е. просто не имеют смысла. Поэтому, когда речь идет о законах Ома, то вся терия цепей автоматически подразумевается как контекст. Ну и в реляционных БД тоже, РА не является самостоятельной прикладной наукой, а является разделом и живет исключительно в контексте теории реляционных БД, вот которая уже и является самостоятельной прикладной наукой. Т.е. является некоей "единицей" знаний. Ну и насчет объемов "знаний" тоже любопытное вышло наблюдение. Если матричное исчисление — это нехилый объемный аппарат, то законы Ома или РА — это сравнительно малое кол-во примитивных формул/операций... в общем, это такой объем "знаний", которые на отдельный учебник претендовать никак не могут. В общем, в плане связи разделов наук друг с другом стоит понимать, что первично, а что вторично. Законы Ома — это инструмент для Теории цепей, которая сама обслуживает задачу вычисления параметров цепей. А в Теории реляционных БД первичная задача — это реляционное исчисление (для нее, родимой, это всё), а РА выступает как подчиненный инструмент для расчетов/реализации этой первичной задачи.
В общем, коль речь зашла о том, насколько "монолитно" у меня в голове это сидит, то скажу, что РА у меня не просто на "одной книжной полке" рядом с СУБД, а максимум одна из глав в одной и той же книге. Т.е. я не умею и не собираюсь оперировать сими понятиями в отрыве друг от друга, по той причине, что РА в отрыве от теории реляционных БД не имеет ни физического, ни математического смысла.
Здравствуйте, vdimas, Вы писали:
V>В общем, коль речь зашла о том, насколько "монолитно" у меня в голове это сидит, то скажу, что РА у меня не просто на "одной книжной полке" рядом с СУБД, а максимум одна из глав в одной и той же книге. Т.е. я не умею и не собираюсь оперировать сими понятиями в отрыве друг от друга, по той причине, что РА в отрыве от теории реляционных БД не имеет ни физического, ни математического смысла.
Ваша позиция понятна. Не вижу смысла продолжать дальнейшую дискуссию, т.к. мы расходимся по принципиальным вопросам. Вы не умеете и не хотите выделять отдельные "слои" понятий — это ваше право. Вы можете искренне считать, что SQL пользуется реляционной моделью, или что в реляционной алгебре есть место подробностям реализации вроде индексов, страниц, кластеризации и прочих потрошков СУБД. Совершенно не факт, что это будет лично вам мешать писать вполне успешные приложения.
Лично мне такое смешение сущностей кажется совершенно диким, но пусть это останется моей проблемой.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
G> б)если А иднетичен Б, то любое изменение А сразу отражается на Б. Это и есть определение ОО-идентичности.
гон и провокация, и опять же нарушение инкапсуляции. мы не можем утверждать когда именно оно применится, мы можем лишь делать утверждения на основе наблюдамого поведения.
и правильная формулировка: в ООП объект А и объект Б считаются одним и тем же(идентичными), если конкретное поведение объекта А и конкретное поведение объекта Б не отличимо друг от друга.
и из этого следует, что:
во-первых: изменение примененное к объекту A _лишь_ должно быть учтено в объекте Б не позднее, чем объект Б сформирует ответ на функцию, которая могла бы выявить, что объект Б отличается от объекта А (ни о каком "сразу" речь не идет)
во-вторых: stateless-объекты вообще таким ограничением не обладают, потому что в контракте у них нет методов, меняющих их состояние, и из этого следует — что, например, два(и более) stateless-объекта, имеющие один и тот же автомат-поведения и созданные с одними и теми же настройками можно считать одним и тем же объектом (идентичными).
из первого пункта, например, следует что объект A и объект Б(который является транспарент-proxy над объектом A) есть один и тот же объект, при этом ни о какой "сразу"-применимости изменений объекта А к объекту Б говорить нельзя
Здравствуйте, DarkGray, Вы писали:
DG>для точного определения ботлнека не хватает статистики(или экспертных оценок): DG>как часто используется ?, какое распределение запросов по длине rack, какое распределение слов в словаре по длине, DG>насколько тормозит файловая система, и как часто файл словаря попадает в memory-кэш ос.
Правильно. Речь именно о том, что для оптимизации нужно применять сбор статистики, а не гадание в уме.
Ваше предсказание основных узких мест получилось лучше, чем у vdimas. Но запуск профайлера всё равно был бы дешевле и точнее.
V>>В общем, коль речь зашла о том, насколько "монолитно" у меня в голове это сидит, то скажу, что РА у меня не просто на "одной книжной полке" рядом с СУБД, а максимум одна из глав в одной и той же книге. Т.е. я не умею и не собираюсь оперировать сими понятиями в отрыве друг от друга, по той причине, что РА в отрыве от теории реляционных БД не имеет ни физического, ни математического смысла. S>Ваша позиция понятна. Не вижу смысла продолжать дальнейшую дискуссию, т.к. мы расходимся по принципиальным вопросам. Вы не умеете и не хотите выделять отдельные "слои" понятий — это ваше право. Вы можете искренне считать, что SQL пользуется реляционной моделью,
Синклер, ты демагог в запущенной стадии этого заболевания, сорри. При чем тут вообще SQL? В 10-й раз!
Ну это же нубство натуральное путать реляционное исчисление, реляционную алгебру и язык SQL. Тем более, что всю взаимосвязь м/у ними тебе оппонент уже дал.
S>или что в реляционной алгебре есть место подробностям реализации вроде индексов, страниц, кластеризации и прочих потрошков СУБД. Совершенно не факт, что это будет лично вам мешать писать вполне успешные приложения.
Я лишь вижу, что ты рассуждаешь о том, о чем на сегодня поленился пройтись хотя бы краем глаза. Вроде уже все входы и выходы я тебе показал, — конкретно, что что РА оперирует над реляционной моделью. Ну дык, стоило бы пройтись по реляционной модели или как? Или опять легче просто ответить "вы путаете SQL и РА". Это же все желание отпадает впредь что-то обсуждать на таком уровне. Смысл? Ты умудряешься повторяться относительно своих же нескольких постов назад, проявляя игнор к аргументам оппонента...
S>Лично мне такое смешение сущностей кажется совершенно диким, но пусть это останется моей проблемой.
Для начала надо понимать, откуда эти сущности берутся. Если пройтись только по несчастным 7-ми операциям, составляющим собственно реляционную алгебру, но пропустить реляционную модель и не прорешать хотя бы пару десятков задач по РА, то в голове может начать твориться что угодно. Я здесь при чем? ИМХО, это может происходить только от непонимания взаимосвязи разделов обсуждаемой прикладной науки — "теория реляционных БД". Крайне рекомендую к прочтению тот самый знаменитый труд Кодда, в которой он представил сию прикладную науку. Все-таки, у любой прикладной науки, в отличие от фундаментальной, обязательно "откуда-то растут ноги". Тем она от фундаментальной и отличается. Любая прикладная наука обязательно представлена как законченное инженерное решение: постановка задачи, анализ, пути решения, выводы. Нельзя понахвататься по верхам, по отдельным элементам некоей прикладной науки, потому как легко упустить взаимосвязь всех компонент этого "решения"... После ознакомления с рекомендованной работой можно было бы продолжить обсуждение, если еще останутся доводы и желание.
Ну и, раз тебя так влечет пример SQL... Не из SQL растут ноги, теории реляционных БД, конечно.
Наоборот, сам SQL растет из реляционного исчисления, но и это не принципиально, бо многие диалекты SQL включают непосредственно операции из РА. Языков, подобных SQL, могло бы гораздо более одного, даже странно, что в ходу разных диалектов очень похожий "общий корень", ну так уж случилось исторически. ИМХО от того, что сама теория реляционных СУБД появилась относительно поздно (я уже родился ), и стандартизация аспектов IT была уже в ходу.
Ну и тыкать в оппонента SQL-ем, это все равно что приписывать ему понимание императивного программирования исключительно в виде языка Паскаля, например... где-то так...
V>> Почему с "индексом" проблемы?..
DG>индексов может и не быть, но реляционная модель будет существовать. DG>элементы же можно искать и без всяких индексов через полный пробег по множеству
Ради бога, если не забыть, что индекс — это таки выделенное отношение. С т.з. РА, "пробег" по отношению, которое мы приняли в кач-ве индекса, ничем не отличается от "пробега" по другому какому-нить другому отношению.
V>Ради бога, если не забыть, что индекс — это таки выделенное отношение. С т.з. РА, "пробег" по отношению, которое мы приняли в кач-ве индекса, ничем не отличается от "пробега" по другому какому-нить другому отношению.
в самой реляционной модели и РА, пока рассматривается только корректность тех или иных операций, никаких "пробегов" еще нет, и соответственно нет индексов.
пробеги и индексы появляются, когда кроме рассмотрения корректности появляется еще рассмотрение скорости выполнения.
соответственно, ты сейчас про какую РА говоришь — ту которая рассматривает только корректность, или ту которая еще рассматривает корректность + скорость?
Здравствуйте, DarkGray, Вы писали:
S>> Так вот, согласно ECMA, эта реальная identity будет всего лишь эквивалентностью, и то лишь при условии выполнения ряда условий из определения эквивалентности.
DG>и фиг с ним. в каких сценариях это будет аукаться?
В сценариях, где можно попутать идентичность объектов. Пример: ты думал что изменил строку и на это рассчитывал в то время как она не изменилась.
DG>мы вон уже выяснили, что даже double полностью не поддерживает идентичность (рефлексивность сооблюдается только на подмножестве всех значений)
Мы выяснили что оператор (==) для double не заменяет идентичность. Но тем не менее, в ECMA определена идентичность для value типов. DG>и когда это последний раз аукалось? и в каких сценариях нельзя рассматривать double (переменную типа double) как объект?
И снова я против того что бы рассматривать переменную как объект. А по поводу double-а, отвечу, что идентичность он таки поддерживает.
DG>или возьмем реальный пример: версионный объект (двух типов). версионный объект при определенных изменениях создает версии своего состояния.
DG>объект с версионностью первого типа: создает версию, если явно его об это попросить DG>
DG>var xv = x.FixVersion();
DG>var y = x;
DG>y.Change1();
DG>
DG>во втором сценарии, версия объекта создается автоматически при изменении объекта DG>
DG>var y = x.Change1();
DG>
DG>в обоих этих сценариях появляется две плоскости: DG>ecma-объекты и логические объекты. (и те и другие удовлетворяют ОО-модели).
DG>что здесь является функцией идентичности для логических объектов?
Вот когда ты определишьь идентичность для "логических объектов", тогда и начнем "логические объекты" рассматривать в качестве объектов ОО системы. А до тех пор, они объекты по ECMA. DG>кстати, эти обе версионности являются эквивалентными: через адаптер можно одну версионность преобразовать к второй версионности, и наоборот.
Какое это имеет значение?
DG>первый вариант версионности назовем backup-версионность DG>второй вариант версионности назовем immutable-версионность
DG>immutable-версионность обладает интересным свойством: ссылка x всегда ссылается на ту версию объекта, которой была проинициализирована, вне зависимости от того, в какой момент времени был произведен реальный вызов.
ОО не знает, что такое версия объекта. Эта версия — это особенность конкретной модели. Причем, версия — самостоятельный объект ОО.
DG>и оказывается, что для сложного кода со сложными оптимизациями (lazy, создание по требованию и т.д.) удобнее работать с объектами с immutable-версионностью: потому что при lazy есть состояние неопределенности, когда произойдет реальный вызов, а immutable-версионность гарантирует, что даже несмотря на эту неопределенность поведение всегда будет одним и тем же.
DG>соответственно, подбирая под каждую неопределенность объекты с определенным поведением(контрактом) можно последовательно сделать так, чтобы неопределенности не мешали выдавать определенное поведение.
Удобнее не связывать lazy с мутабельными сущностями, тогда голова не будет болеть, lazy ли, иммутабл ли, или и то и другое одновременно. И никаких необпределенностей.
S>> Вот послал я объекту сообщение, изменяющее состояние, а почему-то объект с той же "реальной" identity на тысяче остальных клиентов, на это не среагировал. Ну и причем тут ООП?
DG>отличное ООП, просто в контракте на такое сообщение написано, что сообщение может не дойти.
А никакого сообщения тем объектам не посылалось. Согласно ООП оно должно быть послано одному объекту, и все остальные объекты с same identity должны быть неотличимы от тому, которому послали. Но беда в том, что изменив объект на одном клиенте, он не изменится автоматом на сервере, в БД, и на тысяче других клиентов. И если это так, то с такой распределенной identity какая-то фигня.
DG>и отдельно оговаривается, что происходит если не дошел запрос к объекту, и отдельно, если не дошел ответ от объекта.
someObject.UpdateState();
Запрос дошел, ответ получен. Но на 1000е клиентов что-то не так...
DG>и при этом простую ООП-архитектуру можно строить даже поверх таких особенностей(ограничений).
Ты используешь ООП архитектуру для построения некой своей архитектуры, которая имеет отношение к ООП лишь тем что "все есть объект" и построено поверх ООП системы.
DG>тут, кстати, опять же помогают объекты с версионностью второго типа, когда мы четко знаем, какая ссылка на какую версию объекта ссылается. для таких объектов код для разрешения потери сообщения через несколько повторов сообщения пишется элементарно (делаем допущение, что потеря сообщения формирует исключение, в том числе и через клентский-timeout, если ответ не пришел через заданное время): DG>
DG>var y = x.Try(3, _=>_.Change1());
DG>static T Try<T>(this T x, int count, Func<T, T> action)
DG>{
DG> for (int i = 0; i < count; ++i)
DG> {
DG> try
DG> {
DG> return Action(x);
DG> }
DG> catch (Exception exc)
DG> {
DG> if (i == count - 1)
DG> throw;
DG> }
DG> }
DG> throw new ArgumentException("count");
DG>}
DG>
DG>для объектов без версионности, или с backup-версионностью — рассмотрение всех вариантов (сообщение не дошло; сообщение дошло, но объект отказался его обрабатывать(вернул исключение); не дошел ответ и т.д.) и написание кода для корректной обработки всех вариантов — это очень сложная задача, чем обычно и пренебрегают, что видно на реальных программах.
Вообще говоря, в распределенных системах (где сообщение может не дойти туда и обратно), если не используется message passing style, то есть аналог RPC, т.е. запрашивающий знает о том, был ли ответ или исключение. Но со стороны отвечающей стороны никакая версионность не поможет, т.к. отвечающая сторона не может знать, дошел ли ее ответ до запрашивающей, если запрашивающая сторона не вышлет сообщение, подвтерждающее получение ответа. Но запрашивающая сторона может не знать, получила ли отвечающая сторона подтверждение...
Здравствуйте, Sinclair, Вы писали:
V>>Таки настаиваю. Понимаешь, индекс можно построить даже по данным, которые не поддерживают операцию сравнения, хоть этого нельзя конкретно в MS SQL, но это лишь подробности MS SQL. Принципиально в таком индексе будет то, что объем данных проекции может быть гораздо меньше объема всех данных, поэтому операция выборки/ограничения по индексу может быть выполнена многократно эффективнее, чем по всем исходным данным. Вот так может приниматься решение — делать индекс кластерным или некластерным. S>Вы напрасно спорите с очевидным. Если мы рассуждаем исключительно в терминах РА, то нет никакого смысла в "сохранении" результата какой-то операции, т.к. там нет понятия "эффективности".
Это ты откуда берешь? В терминах РА мы всегда выполняем некую последовательность операций, где последующие операции используют результаты предыдущих. Это классическая императивная последовательность действий. Но, доказано, что РА и реляционное исчисление взаимно эквивалентны, т.е. декларативные формулы реляционного исчисления всегда могут быть выражены через императив реляционной алгебры. Вспомним ниже, когда дойдем до SQL.
Насчет эффективности — я даже не знаю, как можно было не понять, о чем речь. Что не так с сохранением частоиспользуемых операций? И повторюсь: для операций РА эффективность является вычислимой. Т.е. берем конкретную операцию из РА, берем некую структуру данных... так вот, для этой пары {операция РА, структура данных} обязательно есть оценка стоимости в терминах K*O(n). И опять же повторюсь, именно так работает оптимизатор, он же не на кофейной гуще гадает...
S>Если мы рассуждаем в терминах RDBMS, то операции "проекция" недостаточно, по двум причинам: S>1. Индекс, помимо "публичных" данных, которые можно получить в результате проекции, хранит обратные ссылки на "строки таблицы". В РА невозможно сослаться на конкретную строку.
Садись, два.
Выделенное неверно. Далее все рассуждения, основанные на этом — тоже. Гуглить по фразе "кортеж однозначно определяется", до кучи можно еще "суррогатный ключ". Понимаешь... в общем, лень толкать банальности, но невозможно вынести из отношения ключ (в общем случае составной) без ввода в процессе декомпозии дополнительного атрибута в оба получившихся отношения для службы в кач-ве суррогатного ключа. Или тебя смущает, что внутренний ключ-bookmark для тебя недоступен? Меня не смущает, коль я знаю, как именно происходит декомпозиция отношений.
S>2. Индекс, помимо "содержания" данных, обладает особенностями их размещения, которые позволяют некоторые операции выполнять быстрее.
Это не важно, для выбора того или иного плана запроса нам от структуры необходима лишь оценка стоимости некоей операции РА над ней, а вовсе не подробности ее реализации. Считай любую структуру черным ящиком с известными характеристиками по каждой операции из РА.
S>В частности, поиск значения ключа в индексе традиционно выполняется за O(log(N)) либо O(N/M), с достаточно большими основаниями логарифма или M для того, чтобы в практических случаях это сводилось к O(1). Некоторые виды индексов также позволяют делать c подобной асимптотикой операции диапазонного поиска.
Плевать, есть разные индексы. В хеш-таблице у меня будет близко к O(n), но это всё не принципиально в нашем обсуждении.
S>Кстати, индекс для данных, не поддерживающих операции сравнения, не имеет никакого смысла.
Имел ввиду операцию сравнения на больше/меньше, конечно, которая обязательная для выполнения индексов в виде деревьев для упомянутого случая MS SQL. Ес-но, операция на равенство в домене должна быть, иначе смысл в индексе на таком домене пропадает, это и так понятно.
V>>Еще раз большими буквами — любой некластерный индекс — это и есть проекция. В классике индексы некластерные изначально. Просто в MS SQL ввиду особенностей хранения блобов кластерные индексы оч популярны. S>Вы продолжаете писать бессмысленный набор слов. Популярность кластерных индексов в MS SQL никак не связана с особенностями хранения блобов, да и вообще с блобами не связана.
Таки настаиваю, потому как встречал разные БД в свое время, в том числе такие, где индексы выделялись как некластерные исключительно для улучшения K при O(n), ввиду банально меньших данных, требуемых для сканирования. А в MS SQL строки таблиц с кластерным индексом имеют фиксированную длину, именно для этого блобы, выше определенной длины, не хранятся в самих таблицах. Их можно разместить где угодно, хоть на других жестких дисках. Поэтому... поэтому просто прочти еще раз, что я там написал. Кстати, неплохая вышла иллюстрация побочного эффекта, возникающего при использовании пропагандируемого подхода, что "необязательно понимать устройство того, с чем работаешь". Не объяснишь, как же ты в своих проектах принимаешь решение, делать некие индексы кластерными или нет? Мне уже очень любопытно услышать этот алгоритм рассуждений.
V>>Я тебе скажу так, в достаточно большой системе, с многими миллионами записей движений и сотнеями справочников, одно лишь только изменение суррогатных ключей с типа int на shortint в справочниках и оформление индексов как некластерных у справочников, где записи достаточно большие (много полей) подняло производительность более чем в четверо. Вот зачем нужна проекция при построении индекса — это снижение объема перелопачиваемых данных при операциях над таблицами, проводимыми по этому индексу/ключу (фактически все операции из РА). S>Я вас разочарую: снижение объема перелопачиваемых данных в индексах выполняется не за счёт операций проекции, а за счёт организации данных.
Ну что ж, так и думал... тебе был дан пример улучшения К при O(n) при всех других прочих равных. Т.е. индекс УЖЕ был, мы лишь вынесли его за пределы остальных данных таблицы и минимизировали объем данных индекса, в итоге получили нифига себе какой профит. Ты понял, что произошло? В терминах O(n) кластерный индекс эквивалентен двоичному дереву, поэтому вынос его за пределы конкретно в MS SQL не изменяет вид характеристики O(n), это была лишь демонстрация того, для чего вообще нужны некластерные индексы и почему пренебрегать К при O(n) вовсе не стоит. А ты не понял примера. Так что, предыдущий вопрос, относительно принятия решений по индексам в твоих проектах, остается в силе.
V>>Наверно не понимаешь, что есть реляционное исчисление, а что есть реляционная алгебра, так? Это совсем не одно и то же. S>И тем не менее, SQL не оперирует понятиями реляционной модели.
Тем не менее, классический SQL оперирует понятиями реляционного исчисления + непосредственно поддерживает некоторые операции РА, а кое-какие диалекты поддерживают еще больше операций РА, чем даже классический SQL-92.
Т.е. конструкции SQL-92 могут однозначно отображаться на язык реляционного исчисления. Обратно неверно, т.к. в реляционном исчислении больше возможностей, чем в SQL-92. Но уже Oracle SQL или Transact SQL имеют чуть большую область взаимного отображения, покрывая целиком реляционное исчисление, + дают возможность выполнять произвольные операции из РА (пусть даже эмулируя их вручную на курсорах и временных таблицах) и вводя еще больше ср-в уже за рамками реляционной модели, в основном за счет всяких императивных конструкций и свободных+внешних ф-ий.
Вот на пальцах разница м/у РА и реляционным исчислением (прямо с первой страницы гугла): http://www.mstu.edu.ru/study/materials/zelenkov/ch_4_5.html
Формулы реляционного исчисления по ссылке даны по-русски, но есть другие известные языки, например QUEL и ALPHA, введенный Коддом. Хотя, они выглядят близко к тому, что в примере, только на английском.
Еще из первой страницы гугла про реляционное исчисление: http://www.ref.by/refs/67/28689/1.html
Эта ссылка напомнила мне краткий конспект того, как именно оно преподавалось нам когда-то.
V>>Я не знаю, что есть логическое, а что есть физическое в твоем понимании? S>Это я вижу. Поясняю: При рассмотрении анатомии оптимизаторов запросов в СУБД, выделяют два вида "планов запроса": S>1. Логический план. Выражается в терминах операций расширенной РА; является результатом синтаксического разбора SQL запроса и некоторой предварительной оптимизации. Предварительные оптимизации на этом этапе имеют целью упрощение плана для дальнейшего анализа и устранение заведомых неоптимальностей. S>2. Физический план. Выражается в терминах императивных операций, работающих над конкретными объектами реляционной базы. Это совсем другие операции. Скажем, там, где в логическом плане была пара операций π и σ, в физическом плане будет одна операция table scan. Или одна операция index seek. Или операция index scan и операция bookmark lookup.
Улыбнуло.
Index scan — это по прежнему операция ограничения из РА, а bookmark lookup — один из видов того самого соединения. Похоже, разный уровень подробностей происходящего застилает от тебя суть вещей... ИМХО, это от того, что ты представляешь себе индексы не как декомпозицию исходного отношения, а нечто "монолитное" (С), присущее данным. Представь индекс как отдельное отношение и всё сразу встанет на свои места. И тогда физический уровень будет уровень формата данных разве что, т.е. именно физическое размещение данных во внешней и оперативной памяти. Потому как ты натурально оперируешь всё еще логическими уровнями разной степени подробности... Так и подумал изначально, поэтому переспросил. Собсно, вот пример абстракций с разной степенью подробностей, о чем мы и спорили изначально, еще до сваливания в тему СУБД.
V>>Использование разного порядка сканирования индексов — это физическое отличие или логическое? S>Конечно же это отличие физического плана. В логическом плане никаких индексов нет.
Сорри, но выделеное профанирует вообще весь спор об абстракциях.
Давай тогда уже так: что есть абстракция на твой взгляд? Может, мы спорим "каждый о своем"? Натурально обидно после стольких постов увидеть, что "в логическом плане никаких индексов нет", это же сколько потраченного времени...
S>В реляционной алгебре нет никаких императивных операций. RTFM.
Угу, смотрю в книгу, вижу известно что. Короче, преобразования данных, выполняемых в терминах РА — это ВСЕГДА императивный алгоритм, построенный на примитивах-операциях РА. Важна последовательность операций, а сами аргументы операций — это результаты (в общем случае) предыдущих операций. Таки решение хотя бы пары десяток задач по РА настоятельно рекомендуется, для прочистки... А до тех пор мы будем обсуждать все эти ньюансы крайне поверхностно. (хоть и с демонстрируемым непонятно откуда пафосом)
Здравствуйте, DarkGray, Вы писали:
V>>Ради бога, если не забыть, что индекс — это таки выделенное отношение. С т.з. РА, "пробег" по отношению, которое мы приняли в кач-ве индекса, ничем не отличается от "пробега" по другому какому-нить другому отношению.
DG>в самой реляционной модели и РА, пока рассматривается только корректность тех или иных операций, никаких "пробегов" еще нет, и соответственно нет индексов. DG>пробеги и индексы появляются, когда кроме рассмотрения корректности появляется еще рассмотрение скорости выполнения.
DG>соответственно, ты сейчас про какую РА говоришь — ту которая рассматривает только корректность, или ту которая еще рассматривает корректность + скорость?
Про "пробег" сказал ты, имея ввиду наверно способы реализации операции "ограничение" (или "ограничения" как часть некоей теоретико-множественной операции РА, т.е. помним что такие операции могут быть выражены через другие операции РА, что принципиально). Т.к. конкретный способ "пробега" не задан, это ничему из РА не противоречит.
Я лишь ответил, что если считать выделение индекса как декомпозицию отношений в классичесской реляционной модели, то твой "пробег" по индексу, т.е. выделенной части декомпозиции, с целью того самого ограничения, ничем не отличается от "пробега" по исходному отношению. Это будет всегда верно в случае корректности проведенной декомпозиции, т.е. такой декомпозиции, которая делает верными все зависимости и ограничения некоей исходной схемы. Напомню, что зависимости исходной схемы всегда задаются как зависимости м/у аттрибутами, а вовсе не отношениями. Простейший пример: есть некая схема R {ABCD}, и заданы зависимости A->B, B->CD. Для этой схемы будет уместна декомпозиция {AB, BCD}, причем, в реальной СУБД мы во втором отношении можем создать индекс B, сугубо эффективности ради, но! это будет означать лишь еще раз произвести декомпозицию по всем правилам декомпозиций с вводом специального аттрибута-ключа B#, для требований сохранения исходной зависимости B->CD транзитивно через B->B#, B#->CD. В итоге получим декомпозицию заданной схемы в виде: {AB, BB#, B#CD}.
В общем, по данной выше ссылке я попытался продраться через всевозможные предрассудки и поверхностность... я бы уже с этой "терминологической борьбой" завязывал бы, потому как в качестве ликбеза пора бы начинать постить сюда и решать пошагово задачи по реляционному исчислению и реляционной алгебре.
Здравствуйте, DarkGray, Вы писали:
G>> б)если А иднетичен Б, то любое изменение А сразу отражается на Б. Это и есть определение ОО-идентичности.
DG>гон и провокация, и опять же нарушение инкапсуляции. мы не можем утверждать когда именно оно применится, мы можем лишь делать утверждения на основе наблюдамого поведения.
Не в этом дело. Дело в том что совпадение identity в ООП говорит о том что это один и тот же объект, и свойство, описанное выше в данном случае тривиально и очевидно.
DG>и правильная формулировка: в ООП объект А и объект Б считаются одним и тем же(идентичными), если конкретное поведение объекта А и конкретное поведение объекта Б не отличимо друг от друга.
Нет, это ты привел определение эквивалентности. Для отношение идентичности требуется чтобы оно от поведения не зависело. http://www.objectarchitects.de/ObjectArchitects/orpatterns/index.htm?OID/index.htm
Исследования для одного из случаев...
Опять же, для первой итерации потянет. Пример подробно не смотрелся... так же сказалось отсутствие навыков беглого чтения LINQ (почти не юзаем в работе), есть такое. Если взглянуть внимательней, то racks.Contains() — действительно жесть... Там напрашивается ровно обратное сравнение: allWords[result.Length].ContainsKey(result), происходящее еще на этапе ReplaceQuestionMarks.
Здравствуйте, DarkGray, Вы писали:
S>>Но запуск профайлера всё равно был бы дешевле и точнее.
DG>это верно(особенно последнее) только при совпадении множества факторов: DG>1. совпадают окружения при запуске профайлера и реальное окружение. DG>2. совпадает набор запросов подаваемый программе под профайлером и набор запросов прогоняемый в реальном окружение. DG>3. профайлер умеет собирать относительную (условную) статистику (или это учтено при в сценарии использования профайлера) DG>4. правильно зафиксировано и учтено при профайлинге, что именно оптимизируется: среднее время запроса, верхняя граница обработки запроса, достаточность быстродействия и т.д.
DG>зы DG>в моем понимании, хороший программист должен уметь строить модель узких мест своих программы прямо по коду, используя профайлер лишь для проверки и корректировки своего понимания
Прочитай пост Липперта по ссылке:
* Set meaningful, measurable, customer-focused goals.
* Write the code to be as clear and correct as possible.
* Carefully measure your performance against your goals.
* Did you meet your goal? Great! Don't waste any time on performance analysis. Spend your valuable time on features, documentation, bug fixing, robustness, security, whatever.
* If you did not meet your goal, use tools to discover what the worst-performing fixable thing is, and fix it.
Нету здесь пункта "строить модель узких мест". Если в коде еще есть ленивость и\или асинхронность, то единственный способ — мерить. Даже предполагать что-то нельзя.
V>А стоимость самого получения racks не изучал? Мне навскидку показалось, что размер racks будет относительно небольшой в большинстве случаев (сотни элементов в среднем), но дорогой в получении.
там сложность примерно: кол-во возвращаемый слов * (~2 пробега по слову + 2 копирования слова + кол-во '?' * прокрутка "такта" enumerable)
кол-во возвращаемых слов зависит экспонециально от кол-ва '?': 26^кол-во '?'
итого сложность в обработанных символах:~4*длина запроса*26^кол-во '?'
соответственно, пока кол-во '?' небольшое 0-3, то вклад будет небольшим по сравнению с пробегом по 2мб словаря.
Здравствуйте, gandjustas, Вы писали:
G>Прочитай пост Липперта по ссылке:
G>
G>* Set meaningful, measurable, customer-focused goals.
G>* Write the code to be as clear and correct as possible.
G>* Carefully measure your performance against your goals.
G>* Did you meet your goal? Great! Don't waste any time on performance analysis. Spend your valuable time on features, documentation, bug fixing, robustness, security, whatever.
G>* If you did not meet your goal, use tools to discover what the worst-performing fixable thing is, and fix it.
G>Нету здесь пункта "строить модель узких мест". Если в коде еще есть ленивость и\или асинхронность, то единственный способ — мерить. Даже предполагать что-то нельзя.
Это верно в той области ПО, для которой эффективность не является конкурентным преимуществом. Например, для заказного ПО, там же никакой конкуренции... Нужна лишь некая "достаточная" производительность.
А в коробочном ПО в реальности бывает так, что профайлер показывает до 30% затрат на всего одну из самых затратных операций, но она никак не оптимизируема, всё, упёрлись в предел. Зато остальное можно подтянуть, то самое, которое 1-2% каждое в среднем, но примерно вдвое общую эффективность поднять, подняв каждую из мелочей многократно. Это из реальной практики... Для каждого такого случая нужны банально идеи, бо показания профайлера тебе код не напишут.
Есть еще момент: эффективность не всегда определяется пропускной способностью, зачастую идет требования минимизации latency (у нас по работе, например), а в этом деле, когда речь идет о единицах микросекунд, профайлерами уже и близко не пахнет.
G>* Set meaningful, measurable, customer-focused goals.
G>* Write the code to be as clear and correct as possible.
G>* Carefully measure your performance against your goals.
G>* Did you meet your goal? Great! Don't waste any time on performance analysis. Spend your valuable time on features, documentation, bug fixing, robustness, security, whatever.
G>* If you did not meet your goal, use tools to discover what the worst-performing fixable thing is, and fix it.
не вижу где написано, что программист не должен уметь оценивать производительность своего кода без профайлера.
G>Если в коде еще есть ленивость и\или асинхронность, то единственный способ — мерить. Даже предполагать что-то нельзя.
это лишь означает, что некоторые не умеют готовить ленивость или асинхроность.
зы
и на всякий случай напишу очевидные вещи:
1. через профайлер можно прогнать лишь ограниченное кол-во сценариев, которое много меньше, чем поддерживаемое программой кол-во сценариев
2. bottleneck необходимо уметь обнаруживать до того, как на него наткнутся в реальном применении (особенно это актуально для защиты от DDOS)
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Прочитай пост Липперта по ссылке:
G>>
G>>* Set meaningful, measurable, customer-focused goals.
G>>* Write the code to be as clear and correct as possible.
G>>* Carefully measure your performance against your goals.
G>>* Did you meet your goal? Great! Don't waste any time on performance analysis. Spend your valuable time on features, documentation, bug fixing, robustness, security, whatever.
G>>* If you did not meet your goal, use tools to discover what the worst-performing fixable thing is, and fix it.
G>>Нету здесь пункта "строить модель узких мест". Если в коде еще есть ленивость и\или асинхронность, то единственный способ — мерить. Даже предполагать что-то нельзя.
V>Это верно в той области ПО, для которой эффективность не является конкурентным преимуществом. Например, для заказного ПО, там же никакой конкуренции... Нужна лишь некая "достаточная" производительность.
Да-да-да. Забавная байка. У тебя есть сведения о корреляции производительности и продаж для определенного класса программ? Уверен что нет, тогда зачем ты продолжаешь повторять то что не доказано?
С другой стороны "достаточная производительность" явно вытекает из экономической целесообразности: нем смысла тратить на оптимизацию больше чем нужно.
V>А в коробочном ПО в реальности бывает так, что профайлер показывает до 30% затрат на всего одну из самых затратных операций, но она никак не оптимизируема, всё, упёрлись в предел. Зато остальное можно подтянуть, то самое, которое 1-2% каждое в среднем, но примерно вдвое общую эффективность поднять, подняв каждую из мелочей многократно. Это из реальной практики... Для каждого такого случая нужны банально идеи, бо показания профайлера тебе код не напишут.
А ты вообще прочитал то что я процитировал? В 5 пункте fixable слово видел?
V>Есть еще момент: эффективность не всегда определяется пропускной способностью, зачастую идет требования минимизации latency (у нас по работе, например), а в этом деле, когда речь идет о единицах микросекунд, профайлерами уже и близко не пахнет.
А чем пахнет? ты ведь как-то меряешь этот самый latency или ты по коду пытаешься его угадать?
V>>Я лишь ответил, что если считать выделение индекса
DG>зачем вообще нужны индексы? в чем их point?
Ну, автор теории реляционных БД вводит индексы исключительно как ср-во повышения эффективности доступа к данным. Напомню, что теория реляционных БД была разработана как ср-во борьбы с медленными внешними накопителями, поэтому в классике (в самых первых реляционных СУБД) индексы, помимо некоей упорядоченности, несут смысл ограничения физического кол-ва данных, которые требуется прочесть из внешней памяти в оперативную, то бишь доступную для обработки. Поэтому я и талдычу (сорри, конечно, сам себе уже надоел), что индекс стоит рассматривать как декомпозицию исходного отношения. Например, декомпозицию с вводом доп. аттрибута — суррогатного ключа. Продолжают ли при этом исходные аттрибуты отношения, входящие в индекс, храниться вместе с исходными данными, т.е. будет ли избыточность на уровне реализации механизма такого индекса, — меня не интересует вообще.
Почему именно декомпозиция с вводом доп. аттрибута? Ну просто же (рассуждения для случая уникального индекса): по определению такого индекса должно существовать однозначное соответствие м/у кортежом индекса и кортежом исходного отношения, правильно? Т.е. в кортеже индекса должен храниться некий внешний ключ (термин из теории реляционных БД) однозначно определяющий кортеж остатка декомпозиции исходного отношения. Спор, похоже, подогревается тем, что коль физический характер такого суррогатного ключа нам недоступен, мы не можем использовать его в рассуждениях. Дудки, еще как можем, ведь наличие такого соответствия аксиоматично из определения самого понятия "индекс", но просто дается на откуп конкретной схеме реализации индекса.
Итого, как это есть на самом деле: берем отношение ABCD, в нем есть некий ключ (необязательно первичный) AB, т.е. была задана свыше зависимость AB->CD, выносим этот индекс через суррогатный ключ X# (тот самый, ндоступный для непосредственнго оперирования в большинстве СУБД, а в некоторых СУБД таки доступный!), получаем декомпозицию зависимостей: AB->X#, X#->CD. В реальности, как говорил, исходные данные индекса могут храниться избыточно вместе с остальными данными, т.е. иметь место такая декомпозици схемы: {ABX#, X#ABCD}. Более того, для случая X#ABCD сам X# физически не обязан храниться в кортеже (физический уровень в IT — это уровень размещения данных по адресам/байтам/смещениям), хотя обязан являться являться неким его св-вом (т.е. атрибутом), например, порядковым номером или еще каким-нибудь значением в какой-нибудь разновидности адресации. И мы таки обязаны этим атрибутом оперировать в рассуждениях, если хотим выразить операции над индексами в терминах РА.
Здравствуйте, DarkGray, Вы писали:
G>>Еще раз читай то что я процитировал. Первый пункт.
DG>значит ты в слово meaningful включаешь в том числе, чтобы код был понятен и с точки зрения его производительности. DG>о чем тогда дискуссия?
Там написано "set goals". Надо задать цели, причем они должны быть измеримы. Это значит что можно получить ответ достигуты они или нет.
Например "выдерживать нагрузку 100500 одновременных активных пользователей на таком-то железе", вполне можно запустить профайлер с таким сценарием.
В вот "выдерживать как можно большее количество пользователей на любом железе" — уже не получится.
Причем достижение первой цели не требует дополнительных знаний, а только последовательных замеров и устранения ботнеков.
DG>>зачем вообще нужны индексы? в чем их point?
V>Ну, автор теории реляционных БД вводит индексы исключительно как ср-во повышения эффективности доступа к данным.
отсюда и получается, что пока речь идет лишь о корректности преобразованиий РА, то никаких индексов еще нет.
Здравствуйте, vdimas, Вы писали:
V>Это ты откуда берешь? В терминах РА мы всегда выполняем некую последовательность операций, где последующие операции используют результаты предыдущих.
В РА нет изменяемого состояния, поэтому она не более императивна, чем ФП.
V>Но, доказано, что РА и реляционное исчисление взаимно эквивалентны, т.е. декларативные формулы реляционного исчисления всегда могут быть выражены через императив реляционной алгебры. Вспомним ниже, когда дойдем до SQL.
V>Насчет эффективности — я даже не знаю, как можно было не понять, о чем речь. Что не так с сохранением частоиспользуемых операций? И повторюсь: для операций РА эффективность является вычислимой. Т.е. берем конкретную операцию из РА, берем некую структуру данных... так вот, для этой пары {операция РА, структура данных} обязательно есть оценка стоимости в терминах K*O(n). И опять же повторюсь, именно так работает оптимизатор, он же не на кофейной гуще гадает...
Всё правильно, только оптимизатор работает не с РА, а со значительно более низким уровнем. Попробую объяснить на более простом примере: возьмем, скажем, комплексные числа. С точки зрения математики комплексных чисел, операция умножения a * b не имеет никакой "стоимости". А вот если мы перейдём к некоторому представлению комплексных чисел в компьютере, то операция a * b будет иметь некоторую реализацию в этом представлении. И вот уже у этой реализации будет некоторая стоимость, выраженная в терминах более низкоуровневых операций. Именно это даёт возможности реализации, скажем, операции "быстрого" умножения комплексных чисел, которая экономит одно умножение за счёт сложения. Быстрота этого умножения имеет смысл в том случае, если относительная стоимость скалярного умножения по сравнению со сложением велика.
V>Садись, два. V>Выделенное неверно. Далее все рассуждения, основанные на этом — тоже.
ОМГ, какой апломб. Я поскипаю нерелевантные рассуждения, ок? Вопрос не в том, чтобы "однозначно определить". Вопрос в том, чтобы имея bookmark, получить по нему значение записи за O(1).
Вы вот проигнорировали мой пример, а напрасно. Вот у вас есть отношение (id, name, age). Предположим, мы знаем, что name — уникально. Вы хотите найти по name значение age. Стоимость этой "операции" — O(N), где N — количество кортежей в отношении. Это дорого. Что вы сделаете для ускорения? Какая операция проекции даст вам хоть какую-то пользу?
Правильный ответ — никакая. Потому что вы никак не измените N. Единственный способ бороться с O(N) — это построить индекс, т.е. упорядоченное отношение (name, RID), где RID — это внутренний идентификатор записи, учитывающий особенности размещения, и позволяющий делать lookup за O(1).
V>Это не важно, для выбора того или иного плана запроса нам от структуры необходима лишь оценка стоимости некоей операции РА над ней, а вовсе не подробности ее реализации. Считай любую структуру черным ящиком с известными характеристиками по каждой операции из РА.
V>Плевать, есть разные индексы. В хеш-таблице у меня будет близко к O(n), но это всё не принципиально в нашем обсуждении.
Если у вас в хеш-таблице близко к O(N), значит вы плохо реализовали хеш-таблицу.
V>Имел ввиду операцию сравнения на больше/меньше, конечно, которая обязательная для выполнения индексов в виде деревьев для упомянутого случая MS SQL. Ес-но, операция на равенство в домене должна быть, иначе смысл в индексе на таком домене пропадает, это и так понятно.
Хорошо.
V>Таки настаиваю, потому как встречал разные БД в свое время, в том числе такие, где индексы выделялись как некластерные исключительно для улучшения K при O(n), ввиду банально меньших данных, требуемых для сканирования. А в MS SQL строки таблиц с кластерным индексом имеют фиксированную длину, именно для этого блобы, выше определенной длины, не хранятся в самих таблицах. Их можно разместить где угодно, хоть на других жестких дисках. Поэтому... поэтому просто прочти еще раз, что я там написал. Кстати, неплохая вышла иллюстрация побочного эффекта, возникающего при использовании пропагандируемого подхода, что "необязательно понимать устройство того, с чем работаешь". Не объяснишь, как же ты в своих проектах принимаешь решение, делать некие индексы кластерными или нет? Мне уже очень любопытно услышать этот алгоритм рассуждений.
В MS SQL строки таблиц вообще всегда имеют ограничение по длине. Это никак не связано с наличием или отсутствием кластерных индексов. Это связано со страничной организацией хранилища (Возможно, в новых версиях это изменили, но во времена, когда я с ним работал, размер кортежа был ограничен 8000 байт).
Поэтому алгоритм выбора кластерности индекса связан в первую очередь с эффективностью операций по этому индексу. Есть несколько соображений:
1. Для кластерных индексов не нужно делать bookmark lookup. Поэтому имеет смысл делать кластерный индекс по тому ключу, по которому чаще всего происходит поиск разнообразной информации.
2. В случае наличия кластерного индекса, остальные индексы вместо RID используют ключ кластерного индекса. Поэтому не стоит делать кластерный индекс по длинному ключу, если других индексов много.
3. Поскольку кластерный индекс определяет физический порядок расположения записей, то не стоит делать его по монотонному ключу, если в таблицу будет идти интенсивная вставка из многих потоков — это уменьшит коэффциент параллельности.
В общем, всё. Как видим, блобы тут вовсе не участвуют.
V>Тем не менее, классический SQL оперирует понятиями реляционного исчисления + непосредственно поддерживает некоторые операции РА, а кое-какие диалекты поддерживают еще больше операций РА, чем даже классический SQL-92.
Классический SQL не оперирует понятиями реляционного исчисления.
V>Взаимосвязь SQL с реляционным исчислением и алгеброй там же: http://www.mstu.edu.ru/study/materials/zelenkov/ch_4_6_1.html
Вы сами-то это читали?
В то же время SQL подвергается суровой критике как раз за недостаточное соответствие реляционным принципам
V>Еще из первой страницы гугла про реляционное исчисление: http://www.ref.by/refs/67/28689/1.html V>Эта ссылка напомнила мне краткий конспект того, как именно оно преподавалось нам когда-то.
V>>>Я не знаю, что есть логическое, а что есть физическое в твоем понимании? S>>Это я вижу. Поясняю: При рассмотрении анатомии оптимизаторов запросов в СУБД, выделяют два вида "планов запроса": S>>1. Логический план. Выражается в терминах операций расширенной РА; является результатом синтаксического разбора SQL запроса и некоторой предварительной оптимизации. Предварительные оптимизации на этом этапе имеют целью упрощение плана для дальнейшего анализа и устранение заведомых неоптимальностей. S>>2. Физический план. Выражается в терминах императивных операций, работающих над конкретными объектами реляционной базы. Это совсем другие операции. Скажем, там, где в логическом плане была пара операций π и σ, в физическом плане будет одна операция table scan. Или одна операция index seek. Или операция index scan и операция bookmark lookup.
V>Улыбнуло.
Рад за ваше чувство юмора.
V>Index scan — это по прежнему операция ограничения из РА, а bookmark lookup — один из видов того самого соединения.
Нет. V>Похоже, разный уровень подробностей происходящего застилает от тебя суть вещей... ИМХО, это от того, что ты представляешь себе индексы не как декомпозицию исходного отношения, а нечто "монолитное" (С), присущее данным.
Индексы не являются "декомпозицией" исходного отношения. Чтобы начать разговаривать об индексах, нам придётся перейти от абстрактного термина "отношение" к конкретному термину "таблица", и начать учитывать подробности хранения данных. Вы почитайте учебник по устройству СУБД — того же Гарсиа-Молина. Оптимизатор "видит" совсем другую модель, чем вы в ваших задачках по РИ.
Просто большинство "учебников" остаются на уровне плохого пересказа РА и РИ, с внезапным перепрыгиванием в сторону SQL (избегая обсуждения природы различий между SQL и абстрактной реляционной моделью), и, собственно, всё. Следующие учебники уже берут с места в карьер изложение подробностей конкретной СУБД, опять же избегая обсуждать связь этих подробностей с реляционной моделью.
V>>>Использование разного порядка сканирования индексов — это физическое отличие или логическое? S>>Конечно же это отличие физического плана. В логическом плане никаких индексов нет. V>Сорри, но выделеное профанирует вообще весь спор об абстракциях.
К сожалению нет. Вы, похоже, как-то неправильно представляете себе устройство оптимизаторов запросов и связанные с этим теории. Поймите, что если мы попробуем засунуть индексы внутрь логического плана, то сразу же потеряем возможности по оптимизации. Ведь физический план обязан соответствовать логическому.
V>Давай тогда уже так: что есть абстракция на твой взгляд? Может, мы спорим "каждый о своем"?
Очень на то похоже. Я не очень понимаю ваш вопрос. Своё видение того, как всё устроено, я изложил. На всякий случай приведу его ещё раз:
1. Есть Реляционная Модель. Грубо говоря, построена на теории множеств, вводит некоторое математическое пространство.
1.а Есть неразрывно связанные с РМ Реляционная Алгебра (механизм по конструированию из одних отношений других) и РИ (механизм по описанию уравнений над реляционной моделью)
Это пока что всё один и тот же уровень абстракции. На нём мы получаем полезные вещи типа Теоремы Кодда, а также несколько соотношений эквивалентности между операциями РА
2. Есть модель SQL. В зависимости от версии стандарта, обладает разными особеннностями. Она отдалённо напоминает Реляционную Модель, но существенно отличается от неё в важных нюансах. В частности, введены понятия NULL и трёхзначной логики, а также явным образом разрешены дубликаты в таблицах (в отличие от отношений). Эти отклонения внедрены как компромисс между простотой РМ и требованиями удобства в реальных задачах. Важный нюанс: напрямую модель SQL нигде не ссылается на реляционную модель; все взаимосвязи — исключительно идеологические, на уровне "о, отдалённо похожую штуку мы видели и там". Реально сходство примерно такое же, как между преобразованием Фурье и поворотом векотор в трёхмерном пространстве.
2.а. Помимо черт реляционной модели, в SQL есть также черты теории транзакций. Как и в случае РМ, модель SQL привносит в чистую транзакционную теорию некоторые важные модификации, в частности вводит понятие уровней изоляции. Это понятие очень часто неверно интерпретируется разработчиками из-за отстутствия вменяемой литературы, покрывающей зазор между теорией и практикой.
2.б. Существенная роль в модели SQL отводится элементам, которых в математических моделях вовсе не было. Это всяческие view, триггеры, индексы, хранимые процедуры и прочая кунсткамера.
3. Есть модели реализации конкретных СУБД.
3.а. В них добавляются расширения модели стандартного SQL
3.б. А также придаётся конкретный смысл абстрактным понятиям модели SQL.
Именно на этом уровне работают оптимизаторы запросов. Большинство промышленных СУБД позволяют разработчику самому выбирать, на каком уровне абстракции работать — 2, 3а, или 3b. То есть я могу просто написать select age from person where name = 'vdimas', оставаясь в рамках SQL-92. Могу воспользоваться расширениями конкретной СУБД, создав, скажем, table-valued функцию для того же запроса. А могу опуститься на уровень реализации, хинтами вынудив оптимизатор использовать специфический индекс.
V>Натурально обидно после стольких постов увидеть, что "в логическом плане никаких индексов нет", это же сколько потраченного времени...
Срыв покровов произошёл? Ничего, со временем в голове всё устаканится.
V>Угу, смотрю в книгу, вижу известно что. Короче, преобразования данных, выполняемых в терминах РА — это ВСЕГДА императивный алгоритм, построенный на примитивах-операциях РА. Важна последовательность операций, а сами аргументы операций — это результаты (в общем случае) предыдущих операций.
Вы попробуйте хотя бы читать те ссылки, которые сами приводите.
В частности, ни один из подходов нельзя назвать « более непроцедурным « по сравнению с другим.
Это чтобы вы не думали, что РА как-то фундаментально менее декларативна, чем РИ.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>зы DG>в моем понимании, хороший программист должен уметь строить модель узких мест своих программы прямо по коду, используя профайлер лишь для проверки и корректировки своего понимания
В моём понимании, главная характеристика хорошего программиста — понимание собственной органиченности. Пока программист использует свою интуицию и умение строить модель узких мест программы в уме лишь как подсказки для возможных направлений поиска узких мест инструментальными методами, всё хорошо. Но когда он начинает думать, что он и без профайлера молодец — это тупик. Рано или поздно такой программист начнёт заниматься ерундой.
Вот мы разобрали примитивную, крошечную программу, которая работает в идеальных условиях — один поток, один запрос, нет конкурирующих за ресурсы приложений. И то уже наблюдаются значительные сложности в предсказаниях узких мест.
В реальных программах всё гораздо хуже и запутаннее. Без измерений можно потратить месяц на вылизывание кусочка кода, который почти не повлияет на общую производительность.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>И снова я против того что бы рассматривать переменную как объект.
есть глубокое непонимание, что такое модель.
модель — это подобие исходной системы, причем выводы сделанные для модели — справедливы и для исходной системы.
модель устроена как набор допущений, набор следствий из этих допущений и доказательства, что любая система, которая соответствует данным допущениям будет иметь и соответствующие следствия.
при этом модель к исходной системе можно "приложить" в любой момент, проверив что допущения выполняются, сделать выводы о исходной система на основе модели, и также в любой момент модель можно отложить.
из этого в частности следует, что к одной и тоже системе модель может быть "приложена" по разному в один и тот же момент времени.
ни ты, ни sinclair, ни gandjustas так до сих пор и не описали, какие допущения для ООП делаются, какие из этого следствия вытекают, и как это всё доказывается. хотя я неоднократно это просил.
допустим, что для ООП достаточно следующих допущений:
1. можно выделить объекты
2. для объектов есть функция идентичности, определяющую что такое один и тот же объект
3. взаимодействие представлено в виде обмена сообщений
следствие:
если вышеуказанные допущения выполняются, то применим ООП-аппарат.
из всего это следует, что как только для переменной все эти допущения выполняются, то она автоматически становится объектом в терминах ООП
Опишем эти допущения для переменной:
1. каждую переменную будем рассматривать как отдельный объект
2. в качестве функции идентичности возьмем имя переменной
3. взаимодействие с переменной представимо в виде двух сообщений getvalue/setvalue
вывод:
при данных условиях, переменная есть объект в терминах ООП, и для нее применим весь аппарат ООП.
Здравствуйте, DarkGray, Вы писали:
V>>Ну, автор теории реляционных БД вводит индексы исключительно как ср-во повышения эффективности доступа к данным.
DG>отсюда и получается, что пока речь идет лишь о корректности преобразованиий РА, то никаких индексов еще нет.
А почему операции РА не могут быть применены к самим индексам? Я никак не воткну в этот "запрет". Не обоснуешь?
Индексы — это реально существующие объекты БД, созданные не самой базой, но исключительно разработчиками. Зачем делать вид, будто их нет?
Здравствуйте, vdimas, Вы писали:
V>Исследования для одного из случаев...
О да. "Обещали показать выступление камерного оркестра, а ограничились жалким частным случаем для K равного трём"...
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
V>А почему операции РА не могут быть применены к самим индексам? Я никак не воткну в этот "запрет". Не обоснуешь?
сейчас речь не о том: могут или не могут.
а речь о том: нужны или не нужны индексы в рамках реляционной модели и алгебры?
и ответ — не нужны, пока речь идет лишь о корректности реляционной алгебры.
V>Индексы — это реально существующие объекты БД, созданные не самой базой, но исключительно разработчиками. Зачем делать вид, будто их нет?
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, vdimas, Вы писали:
V>>Это ты откуда берешь? В терминах РА мы всегда выполняем некую последовательность операций, где последующие операции используют результаты предыдущих. S>В РА нет изменяемого состояния, поэтому она не более императивна, чем ФП.
Опять продемагогил... спасибо... ФП не означает отсутствие императивности, оно означает наличие ф-ий как первоклассных объектов языка, только и всего. И с чего бы императивному алгоритму оперировать обязательно иммутабельным состоянием? Чай не ООП...
V>>Насчет эффективности — я даже не знаю, как можно было не понять, о чем речь. Что не так с сохранением частоиспользуемых операций? И повторюсь: для операций РА эффективность является вычислимой. Т.е. берем конкретную операцию из РА, берем некую структуру данных... так вот, для этой пары {операция РА, структура данных} обязательно есть оценка стоимости в терминах K*O(n). И опять же повторюсь, именно так работает оптимизатор, он же не на кофейной гуще гадает... S>Всё правильно, только оптимизатор работает не с РА, а со значительно более низким уровнем.
Ниже уровня РА ничего нет, кроме исходного кода, имплементирующего эти самые операции (как раз на лабораторках по реляционным БД дают задание реализовать набор операций РА по заданному виду контейнера). Пройдись по любым исходникам SQL-серваков для подробностей. Кстати, по исходникам MS SQL я подробно проходился в далеком 98-м, видел таблицы с константами и формулы вычисления стоимости для пар {объект, операция}.
S>Попробую объяснить на более простом примере: возьмем, скажем, комплексные числа. С точки зрения математики комплексных чисел, операция умножения a * b не имеет никакой "стоимости".
Это с т.з. какой матемитики-то? Если в коде идет реализация этого умножения и мне инетересно оперировать в рантайм ее стоимостью, то для нее обязательно заранее будет подсчитана стоимость в неких попугаях. Но давай вернемся к твоей математике. С т.з. терминов O(n) стоимостью единичных операций никто и никогда не пренебрегает, ты не прав, их сумму выносят за скобки в виде единого коэф К при O(n), поэтому в реальных формулах этот K имеет вполне реальную величину.
S>А вот если мы перейдём к некоторому представлению комплексных чисел в компьютере, то операция a * b будет иметь некоторую реализацию в этом представлении.
Да, именно, удивительное противоречие самому себе. Как раз для конкретных реализаций и задают формулы вычисления стоимости конкретных операций.
S>И вот уже у этой реализации будет некоторая стоимость, выраженная в терминах более низкоуровневых операций.
Оно выражено в попугаях обычно, бо конкретная единица измерения вовсе не важна. Просто берут некую машину как эталонную, и для нее задают коэф результатов такой, чтобы стоимости операций в попугаях имели удобный для оперирования числовой диапазон. Это общая практика.
V>>Садись, два. V>>Выделенное неверно. Далее все рассуждения, основанные на этом — тоже. S>ОМГ, какой апломб. Я поскипаю нерелевантные рассуждения, ок? Вопрос не в том, чтобы "однозначно определить". Вопрос в том, чтобы имея bookmark, получить по нему значение записи за O(1). S>Вы вот проигнорировали мой пример, а напрасно. Вот у вас есть отношение (id, name, age). Предположим, мы знаем, что name — уникально. Вы хотите найти по name значение age. Стоимость этой "операции" — O(N), где N — количество кортежей в отношении. Это дорого. Что вы сделаете для ускорения? Какая операция проекции даст вам хоть какую-то пользу? S>Правильный ответ — никакая. Потому что вы никак не измените N. Единственный способ бороться с O(N) — это построить индекс, т.е. упорядоченное отношение (name, RID), где RID — это внутренний идентификатор записи, учитывающий особенности размещения, и позволяющий делать lookup за O(1).
Ну вот, сам же и дошел до всего, надо было лиь сфокусировать твое внимание на этом. Я же говорю, никакого rocket science, всё на поверхности. Вот здесь подробней в последнем абзаце: http://www.rsdn.ru/forum/philosophy/4537996.1.aspx
... для случая X#ABCD сам X# физически не обязан храниться в кортеже (физический уровень в IT — это уровень размещения данных по адресам/байтам/смещениям), хотя обязан являться являться неким его св-вом (т.е. атрибутом), например, порядковым номером или еще каким-нибудь значением в какой-нибудь разновидности адресации.
V>>Это не важно, для выбора того или иного плана запроса нам от структуры необходима лишь оценка стоимости некоей операции РА над ней, а вовсе не подробности ее реализации. Считай любую структуру черным ящиком с известными характеристиками по каждой операции из РА.
V>>Плевать, есть разные индексы. В хеш-таблице у меня будет близко к O(n), но это всё не принципиально в нашем обсуждении. S>Если у вас в хеш-таблице близко к O(N), значит вы плохо реализовали хеш-таблицу.
В Хроме практически не пользуюсь предпросмотром, бо в нем глаза сломать можно из-за мелкого шрифта.
S>В MS SQL строки таблиц вообще всегда имеют ограничение по длине. Это никак не связано с наличием или отсутствием кластерных индексов. Это связано со страничной организацией хранилища (Возможно, в новых версиях это изменили, но во времена, когда я с ним работал, размер кортежа был ограничен 8000 байт).
Ну так что первично, а что вторично? Мне как разработчику видно ровно обратное, фиксированные размеры страниц нужны исключительно для нужд кластерных индексов, которые принципиально живут только в контексте детерминированных размеров. И полно было БД без кластерных индексов с совсем другой организацией памяти.
S>Поэтому алгоритм выбора кластерности индекса связан в первую очередь с эффективностью операций по этому индексу. Есть несколько соображений: S>1. Для кластерных индексов не нужно делать bookmark lookup. Поэтому имеет смысл делать кластерный индекс по тому ключу, по которому чаще всего происходит поиск разнообразной информации. S>2. В случае наличия кластерного индекса, остальные индексы вместо RID используют ключ кластерного индекса. Поэтому не стоит делать кластерный индекс по длинному ключу, если других индексов много. S>3. Поскольку кластерный индекс определяет физический порядок расположения записей, то не стоит делать его по монотонному ключу, если в таблицу будет идти интенсивная вставка из многих потоков — это уменьшит коэффциент параллельности. S>В общем, всё. Как видим, блобы тут вовсе не участвуют.
Ну это залет, это даже полный ппц, я бы сказал.
Кластерный индекс хорош лишь там, где seek по всем данным в процессе двоичного поиска относительно дешев. Т.е. когда размеры таблицы заведомо меньше размера ОП. Для сценариев, где от относительно большой таблицы в процессе поиска требуется относительно малое кол-во значений по ключу, ключ надо делать некластерным. Профит получается многократный. Пример с 4-хкратным профитом я приводил. Надо просто помнить, откуда растут ноги у понятия "индекс" изначально (в первых СУБД не было кластерных индексов, из-за ограничений на размер ОП, очевидно), там же: http://www.rsdn.ru/forum/philosophy/4537996.1.aspx
V>>Тем не менее, классический SQL оперирует понятиями реляционного исчисления + непосредственно поддерживает некоторые операции РА, а кое-какие диалекты поддерживают еще больше операций РА, чем даже классический SQL-92. S>Классический SQL не оперирует понятиями реляционного исчисления.
S>В то же время SQL подвергается суровой критике как раз за недостаточное соответствие реляционным принципам
Про недостаточность взаимного отображения я и сам говорил... Понимаешь, тут уже требуется разбор конструкций SQL и сравнение с операциями РА, а не подобное толкание "дурак, сам дурак".
SQL (Structured Query Language — структурированный язык запросов) основывается на некоторой смеси алгебраических и логических конструкций.
Полностью согласен. В SQL торчат уши как реляционного исчисления, так и примитивов РА.
S>Рад за ваше чувство юмора.
Дык, пора бы знать уже, что в IT есть "физический уровень". ИМХО, прямо сейчас стоит закруглить насчет БД и сделать gosub на "абстракции". Иначе разговор ни о чем.
V>>Index scan — это по прежнему операция ограничения из РА, а bookmark lookup — один из видов того самого соединения. S>Нет.
Достойный аргумент. Ничего если я предположу отсутствие навыков по операциям РА, бо эти вещи как бы аксиоматичны?
S>Индексы не являются "декомпозицией" исходного отношения. Чтобы начать разговаривать об индексах, нам придётся перейти от абстрактного термина "отношение" к конкретному термину "таблица", и начать учитывать подробности хранения данных. Вы почитайте учебник по устройству СУБД — того же Гарсиа-Молина. Оптимизатор "видит" совсем другую модель, чем вы в ваших задачках по РИ.
Ес-но, только что мне мешает видеть ту же самую модель, что и оптимизатор? Как я тогда буду писать эффективные приложения для СУБД, если я не понимаю показания плана оптимизатора? Или вот я разработчик СУБД, с какой радости я не могу прикладывать РА к индексам? Это откуда такие запреты-то? Я не только могу, но я обязан использовать весь этот аппарат, чтобы не породить УГ.
S>Просто большинство "учебников" остаются на уровне плохого пересказа РА и РИ, с внезапным перепрыгиванием в сторону SQL (избегая обсуждения природы различий между SQL и абстрактной реляционной моделью), и, собственно, всё. Следующие учебники уже берут с места в карьер изложение подробностей конкретной СУБД, опять же избегая обсуждать связь этих подробностей с реляционной моделью.
Ну ты бы по классике прошелся. Нет никаких прыжков, есть постановка задачи, анализ, и предложенная модель для решения этого класса задач. И оставь в покое несчастный SQL, это уже какое свербение в одном месте. Во многих учебниках никакого SQL нет, поэтому заканчивай делать вид, что ты видел учебники в глаза кроме руководств к конкретным СУБД. Иначе бы не писал, что пишешь, особенно в плане SQL.
V>>>>Использование разного порядка сканирования индексов — это физическое отличие или логическое? S>>>Конечно же это отличие физического плана. В логическом плане никаких индексов нет. V>>Сорри, но выделеное профанирует вообще весь спор об абстракциях. S>К сожалению нет. Вы, похоже, как-то неправильно представляете себе устройство оптимизаторов запросов и связанные с этим теории.
Да правильно представляю. Исходники смотрел в свое время. Более одной БД. Представляю как есть, хоть и похоже, не так, как это представляешь себе ты.
S>Поймите, что если мы попробуем засунуть индексы внутрь логического плана, то сразу же потеряем возможности по оптимизации. Ведь физический план обязан соответствовать логическому.
Давай возьмем другие термины, вместо "физический" и "логический", ок? А то уже совсем грустно.
S>Очень на то похоже. Я не очень понимаю ваш вопрос. Своё видение того, как всё устроено, я изложил. На всякий случай приведу его ещё раз: S>1. Есть Реляционная Модель. Грубо говоря, построена на теории множеств, вводит некоторое математическое пространство.
Ммм.. скорее вводит терминологию и статические св-ва модели, разве что. На теорию множеств накладывается много ограничений в реляционной модели.
Да, реляционная модель — это исходная в теории реляционных БД абстракция. Реляционная модель определяет границы рассматриваемых сущностей, то бишь задает от самый уровень абстракции.
S>1.а Есть неразрывно связанные с РМ Реляционная Алгебра (механизм по конструированию из одних отношений других) и РИ (механизм по описанию уравнений над реляционной моделью) S>Это пока что всё один и тот же уровень абстракции.
Опять не так. Есть операции над этой моделью (суть над исходной абстракцией), РА-операции НЕ являются независимыми абстракциями, а лишь дополняют терминологию модели в области динамики, давая имена примитивным операциям непосредственно над моделью. Т.е., вот есть некая структура, в вот примитивные (неделимые) операции над ней. Это один и тот же уровень абстракции, бо не происходит ни как уточнения подробностей, ни уменьшения исходного кол-ва подробностей, т.е. это один и тот же уровень согласно самого определения "абстракция".
Далее. Есть реляционное исчисление — это (ты абсолютно правильно сказал) банальные уравнение, заданные в терминах модели. Как и любое уровнение, в уравнениях в РИ заданы характеристики результата, а сами уравнения имеют более одного решения в общем случае. Так вот, я не соглашусь, что любые уравнения — это тот же уровень абстракции, что и термины, которыми уравнение оперирует. Коль уравнение задает вид результата, оно заведомо абстрагируется от действий по получению этого результата. Здесь происходит как в классике, декларативность одних сущностей по отношению к другим. Тот самый более высокий уровень абстракции. Так вот, цель построения реляционной модели была как раз в обслуживании исключительно РИ, бо это РИ шла как исходная (полезная) задача по обработке данных.
S>Итого, минимум 2 уровня абстракции.
Угу, 2, только не таких как у тебя. Ты статическое и динамическое описание модели разнес по разным уровням абстракций, мои поздравления.
Переходя к СУБД мы переходим в область другой принятой терминологии, но пока еще не переходим ни на какой новый уровень абстракций. Например:
единственным способом объявления возможного ключа, отличного от первичного, является явное создание уникального индекса.
Какое красивое соответствие 1-в-1.
S>2. Есть модель SQL.
SQL — это язык программирования, таки. И как любой язык имеет право поддерживать несколько парадигм и встроенных операций разного уровня абстрагирования (т.е. когда одни встроенные операции могут быть реализованы как набор других встроенных операций более низкого уровня). SQL не является непосредственной абстракцией модели всей СУБД сам по себе, собственно, как и любой ЯП, а является лишь языковым ср-вом НАД некоторой абстракцией, над некоторой вычислительной моделью. Не факт, что достаточно полным дял оперирования всей абстракцией СУБД, коль большинство СУБД дают в прикладном АПИ малость больше операций, чем позволяют через свой диалект SQL.
S>Она отдалённо напоминает Реляционную Модель, но существенно отличается от неё в важных нюансах.
Меня аж плющит, когда ты снова и снова сравниваешь SQL с реляционной моделью. Сравнивать язык и модель — ну это просто за рамками здравого смысла. Да еще постоянно пытаешься приписать мне некое "непонимание" SQL. Да, я понимаю его не так как ты, это очевидно, иначе бы меня не плющило от подобных сравнений, но это ничего не доказывает в твоих рассуждениях. Я считаю, что сравнивать языковые ср-ва с самой моделью неграмотно, хотя бы потому, что язык может не обладать полнотой по отношению к модели.
S>В частности, введены понятия NULL и трёхзначной логики
И? Реляционная модель никак не ограничивает область значений доменов. Она ими даже не интересуется. Если некая область хочет включить NULL, Nil, папу_римского — да ради бога. Насчет трехзначной логики аналогично — бредятина. По предикатам в в SQL (например в операции JOIN) всегда только два ветвления, т.е. предикаты приводимы булевскому значению, хоть и неявно. Иначе они не могли бы исопльзоваться как предикаты. Или ты имел ввиду, что есть операции сравнения в домене значений {true, false, NULL}? Ну и какие проблемы? Определи этот домен и операции по нему для конкретной схемы реляционной модели и вперед — конкретно реляционной модели, повторюсь, это по барабану.
S>а также явным образом разрешены дубликаты в таблицах (в отличие от отношений).
Угу, в таблицах с отсутствующим первичным ключом. Разумеется, такие таблицы не могут иметь аналогов из реляционной модели, даже если в таблице нет дубликатов. И единственный доступ к данным — это тупой перебор. А раз так, т.е. раз аппарат реляционного исчисления к ним не применим, я бы эти "фишки" вообще не обсуждал... Ведь для подобных таблиц не требуются никакие теории.
Кстати, уместно вспомнить, что операция union без специального хинта таки убирает дубликаты, прямо как в РА... Это к слову, что SQL не подерживает напрямую операции из РА.
S>Эти отклонения внедрены как компромисс между простотой РМ и требованиями удобства в реальных задачах. Важный нюанс: напрямую модель SQL нигде не ссылается на реляционную модель; все взаимосвязи — исключительно идеологические, на уровне "о, отдалённо похожую штуку мы видели и там".
Тогда не существовало бы теории реляционных БД, коль она не нужна?
S>Реально сходство примерно такое же, как между преобразованием Фурье и поворотом векотор в трёхмерном пространстве.
Я бы скорее сравнил Фурье и корреляцию по сетке частот. По произвольной сетке — это просто корелляция, но по сетке с шагом 1/N — оппа!!! уже преобразование Фурье. Примерно так же. Разница в терминологии и ширине области приложения. Фурье — суть частный случай, но отнюдь не бесполезный из-за этого. Скорее наоборот, самый полезный частный случай был разобран до ниточек и были выведены очень полезные прикладные алгоритмы, на которых живет чуть более чем всё цифровое медиа + все современные сетевые технологии. Поэтому как разработчику в области обработки информации необходимо разбираться, откуда растут ноги Фурье (ведь частичное преобразование Фурье — это опять "просто" корреляция, но иногда достаточно и этого) для написания адекватных приложений, так разарботчик БД должен владеть РА и РИ. Это даже неприлично обсуждать, ИМХО.
S>2.а. Помимо черт реляционной модели, в SQL есть также черты теории транзакций. Как и в случае РМ, модель SQL привносит в чистую транзакционную теорию некоторые важные модификации, в частности вводит понятие уровней изоляции. Это понятие очень часто неверно интерпретируется разработчиками из-за отстутствия вменяемой литературы, покрывающей зазор между теорией и практикой.
Для реляционной модели это неважно. Повторюсь, в РА важна последовательность операций, никакая конкуренция не рассматривается. Транзакционность — это из конкурентной реализации конкретно СУБД следует, более ни от чего. Реализация простейшей СУБД могла бы быть и не конкурентная, а как в классике СМО. В общем, это другой раздел прикладной науки, который мы пока не обсуждали.. но если очень хочешь...
S>2.б. Существенная роль в модели SQL отводится элементам, которых в математических моделях вовсе не было. Это всяческие view, триггеры, индексы, хранимые процедуры и прочая кунсткамера.
Угу, в разделе DDL... Я все ждал, когда же, наконец, прозвучит DDL как "последний аргумент"... Че-то долго ждал.
S>3. Есть модели реализации конкретных СУБД. S>3.а. В них добавляются расширения модели стандартного SQL S>3.б. А также придаётся конкретный смысл абстрактным понятиям модели SQL. S>Именно на этом уровне работают оптимизаторы запросов. Большинство промышленных СУБД позволяют разработчику самому выбирать, на каком уровне абстракции работать — 2, 3а, или 3b. То есть я могу просто написать select age from person where name = 'vdimas', оставаясь в рамках SQL-92. Могу воспользоваться расширениями конкретной СУБД, создав, скажем, table-valued функцию для того же запроса. А могу опуститься на уровень реализации, хинтами вынудив оптимизатор использовать специфический индекс.
Я пока еще не вижу противоречий с примитивами РА. Намомню, что формулы реляционного исчисления имеют в общем случае более одного решения в терминах РА. Сама РА оперирует заданной схемой декомпозиции отношений и зависимостями над атрибутами. Поэтому уместно любое решение, которое подходит под заданные зависимости. Ну, указал ты хинтами предпочтение одного из решений, в чем проблема-то? О чем речь?
V>>Натурально обидно после стольких постов увидеть, что "в логическом плане никаких индексов нет", это же сколько потраченного времени... S>Срыв покровов произошёл? Ничего, со временем в голове всё устаканится.
Да нету никаких индексов на физическом уровне просто. Индексы — это тоже логическая единица модели конкретной СУБД. И к ним все так же применимы операции из РА аж бегом и их таки применяют разработчики СУБД. И как можно пытаться нагнать туману на примитивнейшие вещи и называть это "срывом покровов"? Поделись каким-нить знанием, которое будет новым и интересным, тогда и скажешь так. А пока что ты просто выдаешь собственное представление, в котором еще с первых постов невооруженным взглядом виден большо-о-ой такой провал в теории реляционных БД. Ничего личного, но споры относительно РА я бы предпочел вести в терминах самой РА, взаимоотношения операций, разбора конкретных типовых задач из области РА и т.д., а не путем перестрелки с помощью выхваченных из контекста фраз "из интернета".
V>>Угу, смотрю в книгу, вижу известно что. Короче, преобразования данных, выполняемых в терминах РА — это ВСЕГДА императивный алгоритм, построенный на примитивах-операциях РА. Важна последовательность операций, а сами аргументы операций — это результаты (в общем случае) предыдущих операций. S>Вы попробуйте хотя бы читать те ссылки, которые сами приводите. S>
S>В частности, ни один из подходов нельзя назвать « более непроцедурным « по сравнению с другим.
S>Это чтобы вы не думали, что РА как-то фундаментально менее декларативна, чем РИ.
Я могу еще повторить больими буквами, если не понял — РА всегда оперирует неким последовательным алгоритмом. По другому просто никак. Или покажи обратное на примере из более одного шага в решении или прими как данность.
В общем, опять и снова могу лишь рекомендовать прорешать задачи по РА, с целью проникнуться проблематикой, и чтобы составить затем свое мнение не на вырезанных из контекста фразах, а на личном опыте.
V>>А почему операции РА не могут быть применены к самим индексам? Я никак не воткну в этот "запрет". Не обоснуешь?
DG>сейчас речь не о том: могут или не могут. DG>а речь о том: нужны или не нужны индексы в рамках реляционной модели и алгебры? DG>и ответ — не нужны, пока речь идет лишь о корректности реляционной алгебры.
Ну... в рамках реляционной модели ограничения целостности, например по уникальному ключу, для некоей прикладной схемы задаются вербально, а в конкретных СУБД на индексах. По мне — это просто соответствие одного другому.
V>>Индексы — это реально существующие объекты БД, созданные не самой базой, но исключительно разработчиками. Зачем делать вид, будто их нет?
DG>потому что можно обойтись и без них
Для случая эффективной реализации требований/ограничений целостности — нельзя.
Здравствуйте, gandjustas, Вы писали:
V>>Это верно в той области ПО, для которой эффективность не является конкурентным преимуществом. Например, для заказного ПО, там же никакой конкуренции... Нужна лишь некая "достаточная" производительность.
G>Да-да-да. Забавная байка. У тебя есть сведения о корреляции производительности и продаж для определенного класса программ?
Есть.
G>Уверен что нет, тогда зачем ты продолжаешь повторять то что не доказано?
В личку уже приглашал, заканчивай бубнить одно и то же.
G>С другой стороны "достаточная производительность" явно вытекает из экономической целесообразности: нем смысла тратить на оптимизацию больше чем нужно.
Это в твоей уютной реальности заказного ПО.
V>>А в коробочном ПО в реальности бывает так, что профайлер показывает до 30% затрат на всего одну из самых затратных операций, но она никак не оптимизируема, всё, упёрлись в предел. Зато остальное можно подтянуть, то самое, которое 1-2% каждое в среднем, но примерно вдвое общую эффективность поднять, подняв каждую из мелочей многократно. Это из реальной практики... Для каждого такого случая нужны банально идеи, бо показания профайлера тебе код не напишут. G>А ты вообще прочитал то что я процитировал? В 5 пункте fixable слово видел?
И?
V>>Есть еще момент: эффективность не всегда определяется пропускной способностью, зачастую идет требования минимизации latency (у нас по работе, например), а в этом деле, когда речь идет о единицах микросекунд, профайлерами уже и близко не пахнет. G>А чем пахнет? ты ведь как-то меряешь этот самый latency или ты по коду пытаешься его угадать?
Специальные тесты на производительность нужны, с максимальной изоляцией, чтобы минимизировать паразитную постоянную составляющую измерений.
Здравствуйте, gandjustas, Вы писали:
G>Не написано что должен, следовательно не должен. Элементарная логика.
Ну а я напишу что "должен" и хана твоей "элементарной логике"
G>Более того, не всегда приходится свой код оптимизировать.
Слышали уже. Охотно верим.
G>Счегобы? Многие умеют писать программы используя ленивость и асинхронность. Далеко не все могут предположить по внешнему виду время работы.
Почему? Стоимость переключений потоков — штука известная, стоимость "холостого" и "нехолостого" вызова примитивов синхронизации ОС — тоже. Один раз измерь на своей машине и положи себе на видное место.
G>Пример на форуме показал это очень явно. Даже местные гуры перформанса не смогли сходу обнаружить проблему. Так в коде не было ни ленивости, ни асинхронности, ни десятка уровней косвенности.
Мноею пример еще не разбирался подробно, как это происходит в случае с кодом во время оптимизации. Но пару слабых мест указал при даже при чтении по диагонали. Но DarkGray разобрал подробно и все выкладки дал, ты невнимателен.
DG>>и на всякий случай напишу очевидные вещи: DG>>1. через профайлер можно прогнать лишь ограниченное кол-во сценариев, которое много меньше, чем поддерживаемое программой кол-во сценариев DG>>2. bottleneck необходимо уметь обнаруживать до того, как на него наткнутся в реальном применении (особенно это актуально для защиты от DDOS) G>Еще раз читай то что я процитировал. Первый пункт.
Да подтереться им можно в среде с повышенными требованиями к надежности и отзывчивости. Увы и ах. Даже в разобранном примере рассматривался один и тот же сценарий, хотя там нужно было рассмотреть область как минимум по двум координатам. В общем случае показанный подход — это профанация, хотя потянет как вводный урок для новичков.
Здравствуйте, gandjustas, Вы писали:
G>Причем достижение первой цели не требует дополнительных знаний, а только последовательных замеров и устранения ботнеков.
А если они неустранимы? Т.е. если самая затратная операция неоптимизируема никак? То уже всё или как?
Здравствуйте, Sinclair, Вы писали:
S>В реальных программах всё гораздо хуже и запутаннее. Без измерений можно потратить месяц на вылизывание кусочка кода, который почти не повлияет на общую производительность.
Таки не надо смещать акценты, речь шла конкретно про профайлер. Даже если мы "тупо" замеряем "самый верхний цикл" и видим, что оптимизация некоего куска не приносит бенефитов, с чего бы тратить на него месяц?
DG>>потому что можно обойтись и без них
V>Для случая эффективной реализации требований/ограничений целостности — нельзя.
помнишь раньше говорилось про разделение и про монолиты...
я говорю, что РА изначально рассматривает лишь корректность (и тут индексов еще нет), а ты же сразу к этому подцепляешь эффективность (и тут уже, конечно, индексы появляются). Твой подход приводит к монолитному рассмотрению корректности всегда в сцепке с эффективностью.
из монолитной РА можно выделить два слоя:
РА с точки зрения корректности (и здесь еще нет индексов),
РА с точки зрения корректности + эффективности (и здесь уже есть индексы).
каждый из этих слоев используется для решения своих задач:
1. если хочется посчитать какой путь выполнения будет выигрышнее, то используется второй слой
2. если же хочется доказать, что преобразования используемые данным кодом верные, то достаточно использования первого слоя.
также если захочется расмотреть РА поверх какого-то нового исполнителя (например, ассоциативной памяти), то тоже будет удобнее сначала откатиться на первый слой и доказать, что корректность всех операций РА сохраняются и для данного исполнителя, и дальше заполнить второй слой (эффективность) уже с учетом особенностей этого нового исполнителя.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, vdimas, Вы писали:
V>>Исследования для одного из случаев... S>О да. "Обещали показать выступление камерного оркестра, а ограничились жалким частным случаем для K равного трём"...
Тем не менее, именно так. У нас проводятся исследования малость пошире. Где-то на полтора-два порядка. Хотя согласен, что исследование по ссылке потянет как учебное пособие для новичков.
S>В моём понимании, главная характеристика хорошего программиста — понимание собственной органиченности.
одно из самых серьезных ограничений людей, что легко получить ситуацию: когда представление о проблеме не совпадает с самой проблемой. в эту ситуацию очень легко попасть (и очень многие попадают в нее не раз). И если ориентироваться лишь на профайлер, то вероятность попасть в такую ситуацию очень высокая (измерения и оптимизация делаются в одном месте при одних условиях, а реальная проблема находится в другом месте совсем при других условиях).
чтобы такого не происходило и рекомендуется двойной подход:
сначала составление представления об узких местах в голове, а потом перепроверка с помощью профайлера, с отслеживанием как часто наше представление ошибалось, в чем была причина несовпадения, и устранении пробелов в понимании.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>Это верно в той области ПО, для которой эффективность не является конкурентным преимуществом. Например, для заказного ПО, там же никакой конкуренции... Нужна лишь некая "достаточная" производительность.
G>>Да-да-да. Забавная байка. У тебя есть сведения о корреляции производительности и продаж для определенного класса программ?
V>Есть.
Показывай.
V>>>А в коробочном ПО в реальности бывает так, что профайлер показывает до 30% затрат на всего одну из самых затратных операций, но она никак не оптимизируема, всё, упёрлись в предел. Зато остальное можно подтянуть, то самое, которое 1-2% каждое в среднем, но примерно вдвое общую эффективность поднять, подняв каждую из мелочей многократно. Это из реальной практики... Для каждого такого случая нужны банально идеи, бо показания профайлера тебе код не напишут. G>>А ты вообще прочитал то что я процитировал? В 5 пункте fixable слово видел? V>И?
Прочитай еще раз
V>>>Есть еще момент: эффективность не всегда определяется пропускной способностью, зачастую идет требования минимизации latency (у нас по работе, например), а в этом деле, когда речь идет о единицах микросекунд, профайлерами уже и близко не пахнет. G>>А чем пахнет? ты ведь как-то меряешь этот самый latency или ты по коду пытаешься его угадать? V>Специальные тесты на производительность нужны, с максимальной изоляцией, чтобы минимизировать паразитную постоянную составляющую измерений.
То есть ты все равно меряешь.
Здравствуйте, DarkGray, Вы писали:
DG>я говорю, что РА изначально рассматривает лишь корректность (и тут индексов еще нет), а ты же сразу к этому подцепляешь эффективность (и тут уже, конечно, индексы появляются). Твой подход приводит к монолитному рассмотрению корректности всегда в сцепке с эффективностью.
Ок, выкини эффективность оставь только проверку уникальности. Получишь некий "виртуальный" индекс, типа кластерного.
Какая разница-то? Нет ли здесь случайно путаницы "сущности" из мира ПО и банального физического формата хранения данных? Это будет та же сущность даже с тем же публичным интерфейсом, независимо от внутреннего устройства. Таблица в БД, это ведь тоже нихрена не монолит в реальности, это сложнейшая подсистема с кучей плюшек. Но мы рассматриваем маппинг отношения на таблицы и не потеем по поводу деталей.
DG>из монолитной РА можно выделить два слоя: DG> РА с точки зрения корректности (и здесь еще нет индексов), DG> РА с точки зрения корректности + эффективности (и здесь уже есть индексы).
Здесь исторически торчат уши подробностей храния, таки. Угу.
Есть два основных способа — по столбцам, и по строкам. Есть способ смешанный, через декомпозицию: сначала часть столбцов, где данные идут по строкам, потом остальные столбцы, но опять по строкам. Вот так индексы, собственно, и появились — это выделенная часть данных, над которыми совершается большинство операций. Короче, вопрос в силе: коль для целей хранения данных в некоем конкретном представлении мы провели стандартную декомпозицию, какие проблемы использовать аппарат реляционной теории над этой декомпозицией? Путь этот аппарат недоступен для прикладного программиста, которому виден только SQL, но уж разработчик СУБД просто обязан использовать все наработки из реляционной теории.
Вообще, я не считаю, что из РА что-то следует выделять, это же абстракция — уже всё выделено, что надо. Ты не в ту сторону стрелочки->зависимости ставишь. ИМХО, ровно наоборот: берем любую конкретную частность, и, если удается пренебречь деталями этой частности для достижения соответствия условиям знакомой абстракции, то нам становится доступен весь матаппарат сей абстракции.
Ведь СУБД не из реляционной теории выросли, право, а ровно наоборот: реляционная теория разрабатывалась уже на основе опыта эксплуатации существующих БД, и была разработана с целью иметь обслуживающий их формальный аппарат, как раз для понимания происходящего во всякого всякого рода частностях и их комбинациях. Это что-то вроде "паттернов" (тоже терминология + типовые задачи/операции), только с уклоном в специальную организацию данных, подчиняющуюся реляционной модели. Тебе не пофиг ли, на каком из слоев ты применяешь сии паттерны? Где подходят, там их и применяют.
DG>каждый из этих слоев используется для решения своих задач:
Аппарат для расчетов применим везде, где применим. У нас может быть сколь угодно сложная электрическая схема, например, но мы можем взять любой изолированный участок и посчитать, невзирая на все остальное. Примитивные операции над индексами в этом плане полностью аналогичны — ведь их можно свести к операциям над декомпозициями отношений, сохраняющими св-ва исходной схемы.
DG>1. если хочется посчитать какой путь выполнения будет выигрышнее, то используется второй слой DG>2. если же хочется доказать, что преобразования используемые данным кодом верные, то достаточно использования первого слоя.
Таким алгоритмом невозможно было применять некий матаппарат везде, где он был бы подходящ. Более того, здесь ты волей-неволей подразумеваешь наличие некоего "другого" аппарата расчетов, "специального для индексов", а его в природе не существует, мамой клянусь.
DG>также если захочется расмотреть РА поверх какого-то нового исполнителя (например, ассоциативной памяти), то тоже будет удобнее сначала откатиться на первый слой и доказать, что корректность всех операций РА сохраняются и для данного исполнителя, и дальше заполнить второй слой (эффективность) уже с учетом особенностей этого нового исполнителя.
Ниче не надо, если модель работы твоих сущностей, реализованных поверх этой памяти, будет удовлетворять ограничениям реляционной модели. Можно будет использовать напрямую на любом из "слоев". Все слои — сугубо в твоей голове и артефактах документации, более нигде. А что если я заверчу что-нить покруче, например, многомерные таблицы? Хранение отношений прямо в доменах атрибутов? Не запрещено же... И так с произвольной вложенностью? Смог бы я для каждого нового уровня/слоя использовать один и тот же матаппарат? Да легко!
Здравствуйте, DarkGray, Вы писали:
S>>И снова я против того что бы рассматривать переменную как объект.
DG>есть глубокое непонимание, что такое модель.
Есть
DG>модель — это подобие исходной системы, причем выводы сделанные для модели — справедливы и для исходной системы.
Идеальный газ — модель. Но выводы, сделанные для этой модели справедливы для исходной системы лишь в весьма ограниченных условиях, и с весьма невысокой точностью. Блюдце на черепахе с китами — тоже модель. Она немного подальше от реальной системы, но тем не менее.
DG>модель устроена как набор допущений, набор следствий из этих допущений и доказательства, что любая система, которая соответствует данным допущениям будет иметь и соответствующие следствия.
Палка-палка-огуречик — это модель человечка. Где доказательства? DG>при этом модель к исходной системе можно "приложить" в любой момент, проверив что допущения выполняются, сделать выводы о исходной система на основе модели, и также в любой момент модель можно отложить. DG>из этого в частности следует, что к одной и тоже системе модель может быть "приложена" по разному в один и тот же момент времени.
Какое-то сомнительное следствие на счет "приложена по разному".
DG>ни ты, ни sinclair, ни gandjustas так до сих пор и не описали, какие допущения для ООП делаются, какие из этого следствия вытекают, и как это всё доказывается. хотя я неоднократно это просил.
Проблема в том, что ООП это не модель чего либо. Это инструмент, с помощью которого выполняют модель. И выводы относительно модели не делаются по инструменту безотносительно самой модели.
DG>допустим, что для ООП достаточно следующих допущений: DG>1. можно выделить объекты DG>2. для объектов есть функция идентичности, определяющую что такое один и тот же объект DG>3. взаимодействие представлено в виде обмена сообщений DG>следствие: DG>если вышеуказанные допущения выполняются, то применим ООП-аппарат.
Вообще говоря, эти допущения излишни. Мы можем построить модель солнечной системы из объектов, притом что в рамках этой модели небесные тела не будут получать друг от друга сообщений, да и вообще взаимодействовать не будут.
DG>из всего это следует, что как только для переменной все эти допущения выполняются, то она автоматически становится объектом в терминах ООП DG>Опишем эти допущения для переменной: DG>1. каждую переменную будем рассматривать как отдельный объект DG>2. в качестве функции идентичности возьмем имя переменной DG>3. взаимодействие с переменной представимо в виде двух сообщений getvalue/setvalue DG>вывод: DG>при данных условиях, переменная есть объект в терминах ООП, и для нее применим весь аппарат ООП.
она становится объектом, но лишь в модели АСТ ЯВУ для нужд компилятора... К объектам модели солнечной системы объект переменная никакого отношения не имеет, если конечно модель солнечной системы не предусматривает взаимодействие переменных.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Не написано что должен, следовательно не должен. Элементарная логика.
V>Ну а я напишу что "должен" и хана твоей "элементарной логике"
А ты причем? Ты же не липперт и не дейкстра. Ты даже близко не нашел место в коде, которое больше всего ресурсов потребляет
G>>Счегобы? Многие умеют писать программы используя ленивость и асинхронность. Далеко не все могут предположить по внешнему виду время работы. V>Почему? Стоимость переключений потоков — штука известная, стоимость "холостого" и "нехолостого" вызова примитивов синхронизации ОС — тоже. Один раз измерь на своей машине и положи себе на видное место.
А это тут при чем? Ты же понимаешь что async в C# 5 может завершиться в том же потоке, а может не завершиться вообще. Причем заранее об этом сказать почти нереально.
G>>Пример на форуме показал это очень явно. Даже местные гуры перформанса не смогли сходу обнаружить проблему. Так в коде не было ни ленивости, ни асинхронности, ни десятка уровней косвенности.
V>Мноею пример еще не разбирался подробно, как это происходит в случае с кодом во время оптимизации. Но пару слабых мест указал при даже при чтении по диагонали. Но DarkGray разобрал подробно и все выкладки дал, ты невнимателен.
DG>>>и на всякий случай напишу очевидные вещи: DG>>>1. через профайлер можно прогнать лишь ограниченное кол-во сценариев, которое много меньше, чем поддерживаемое программой кол-во сценариев DG>>>2. bottleneck необходимо уметь обнаруживать до того, как на него наткнутся в реальном применении (особенно это актуально для защиты от DDOS) G>>Еще раз читай то что я процитировал. Первый пункт.
V>Да подтереться им можно в среде с повышенными требованиями к надежности и отзывчивости. Увы и ах. Даже в разобранном примере рассматривался один и тот же сценарий, хотя там нужно было рассмотреть область как минимум по двум координатам. В общем случае показанный подход — это профанация, хотя потянет как вводный урок для новичков.
Который ты не прошел А пост был написан человеком поумнее тебя если что.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Причем достижение первой цели не требует дополнительных знаний, а только последовательных замеров и устранения ботнеков.
V>А если они неустранимы? Т.е. если самая затратная операция неоптимизируема никак? То уже всё или как?
Ну так устраняй вторую самую затратную операцию, потом третью итд.
А если самая затратная не устраняется, то скрой её "затратность" от пользователя.
DG>>есть глубокое непонимание, что такое модель. S>Есть
из последующих примеров видно, что никак нет. Это видно, как минимум из того, что ты приводишь однобокие модели с сильным понижением точности описания, и не приводишь ни одной точной модели.
например, если тебе нужно получить площадь прямоугольной комнаты со стенами 5x4 — ты же не начинаешь считать кол-во квадратиков, которые можно уложить на пол, а просто умножаешь 5 * 4 и получаешь ответ 20, который ты даже считаешь правильным.
на основании чего ты всё делаешь?
на основании того, что математики и геометры доказали, что если в реальном мире есть прямоугольная фигура, то можно построить ее абстрактную мат. модель, и посчитать площадь через умножение сторон, и ответ полученный для модели будет справедливый и для реального объекта.
и этот переход (прямоугольная штука -> прямоугольник -> формула расчета площади прямоугольника -> площать исходной прямоугольной штуки) верен для любой ситуации, если там удается ввести евклидовое пространство и выделить прямоугольную фигуру.
Здравствуйте, gandjustas, Вы писали:
G>>>Не написано что должен, следовательно не должен. Элементарная логика.
V>>Ну а я напишу что "должен" и хана твоей "элементарной логике"
G>А ты причем? Ты же не липперт и не дейкстра. Ты даже близко не нашел место в коде, которое больше всего ресурсов потребляет
Неeжели? Ты точно читал мой ответ и разобрался в исходном примере, чтобы мой ответ понять?
Было написано так:
... ПЕРЕД началом оптимизаций, программу необходимо переписать. ...вместо генерации всех вариантов ReplaceQuestionMarks написать алгоритм непосредственного сравнения паттернов с "??". Т.е. для начала сделать преобразования алгоритмов в терминах O(n)
Тот код, который самый ресурсоемкий, выкидывается на первой же итерации, причем целиком, включая вызваемый ReplaceQuestionMarks, из-за своей линейной пробежки затем по данным. Там оптимизировать начинать еще нечего... Ну это в моей колокольни представлений о том, что же есть оптимизация, а что профанация.
G>>>Счегобы? Многие умеют писать программы используя ленивость и асинхронность. Далеко не все могут предположить по внешнему виду время работы. V>>Почему? Стоимость переключений потоков — штука известная, стоимость "холостого" и "нехолостого" вызова примитивов синхронизации ОС — тоже. Один раз измерь на своей машине и положи себе на видное место. G>А это тут при чем? Ты же понимаешь что async в C# 5 может завершиться в том же потоке, а может не завершиться вообще. Причем заранее об этом сказать почти нереально.
Это гадания на кофейной гуще. Ты должен понимать общий характер сценария и суметь подготовить адекватные данные для него. "Реально/нереально" — разговоры для бедных, асинхронное ожидание на сокете тоже может завершиться синхронно, а может нет, с этим уже черти сколько лет работают и никаких проблем. Повторю для особо понятливых, что стоимость каждого из вариантов надо знать.
V>>Да подтереться им можно в среде с повышенными требованиями к надежности и отзывчивости. Увы и ах. Даже в разобранном примере рассматривался один и тот же сценарий, хотя там нужно было рассмотреть область как минимум по двум координатам. В общем случае показанный подход — это профанация, хотя потянет как вводный урок для новичков. G>Который ты не прошел
G>А пост был написан человеком поумнее тебя если что.
Ох и аргументики у нынешних "спецов" пошли... Хочешь от меня такого же уровня?
A: "Для людей, не умнее тебя, если что."
Такой ответный выпад пойдет?
Продолжим нападки?
Любопытна сама ситуация. Разработчик основного продукта для хомячков этими же хомячками превозносится сегодня на пъедестал. И не смей трогать "авторитета". Прямо-таки обратная связь в действии.
==========
Правда, в отличие от тебя он парень вполне адекватный:
Я являюсь экспертом в семантическом анализе языка C#, но не в эффективной генерации кода для процессоров...
Так что нападок не будет, он не подставляется как ты. Я и охотно верю, что в своем деле он лучше, чем я в его деле.
Здравствуйте, vdimas, Вы писали:
V>Опять продемагогил... спасибо... ФП не означает отсутствие императивности, оно означает наличие ф-ий как первоклассных объектов языка, только и всего. И с чего бы императивному алгоритму оперировать обязательно иммутабельным состоянием? Чай не ООП...
Вы, наверное, хотели сказать мутабельным состоянием? Ну, как бы по определению:
In computer science, imperative programming is a programming paradigm that describes computation in terms of statements that change a program state
V>Ниже уровня РА ничего нет, кроме исходного кода, имплементирующего эти самые операции (как раз на лабораторках по реляционным БД дают задание реализовать набор операций РА по заданному виду контейнера).
ОМГ. Я же подробно объяснил, что операции, выполняемые SQL сервером — совсем не те операции, которые описаны в РА.
S>>Попробую объяснить на более простом примере: возьмем, скажем, комплексные числа. С точки зрения математики комплексных чисел, операция умножения a * b не имеет никакой "стоимости". V>Это с т.з. какой матемитики-то? S>>А вот если мы перейдём к некоторому представлению комплексных чисел в компьютере, то операция a * b будет иметь некоторую реализацию в этом представлении. S>>И вот уже у этой реализации будет некоторая стоимость, выраженная в терминах более низкоуровневых операций.
V>Да, именно, удивительное противоречие самому себе.
Никакого противоречия нет. Вы по-прежнему не можете отличить абстрактную математику от её реализации? Печально.
Ваши идеи про "скрытые атрибуты" я понял. К сожалению, они вам не помогут. Для начала, ничего подобного в реляционной модели нет, и с точки зрения алгебры вы вводите просто тавтологии, т.е. отношения, не содержащие новой информации.
Во-вторых, в реляционной модели нет понятия порядка, поэтому вам не удастся, оставаясь в рамках неё, рассчитать стоимость операций над отношениями.
V>Ну так что первично, а что вторично? Мне как разработчику видно ровно обратное, фиксированные размеры страниц нужны исключительно для нужд кластерных индексов, которые принципиально живут только в контексте детерминированных размеров.
Вы делаете сразу несколько неверных утверждений.
1. Кластерному индексу всё равно, ограничен размер записи или нет.
2. Фиксированные размеры страниц нужны для унификации алгоритмов доступа и распределения памяти.
V>И полно было БД без кластерных индексов с совсем другой организацией памяти.
Это вы dBase имеете в виду? У всех остальных известных мне СУБД организация памяти по-прежнему страничная.
V>Ну это залет, это даже полный ппц, я бы сказал. V>Кластерный индекс хорош лишь там, где seek по всем данным в процессе двоичного поиска относительно дешев. Т.е. когда размеры таблицы заведомо меньше размера ОП.
Вы бредите? Seek по ключу индекса дёшев всегда, и никак не требует ограничения размеров таблицы. Я вам привёл подробные условия превосходства кластерного индекса над некластерным. Что именно вам непонятно?
V>Ну оставайся при своем.
Почему "при своём"? Я же давал ссылку:
The current ISO SQL standard doesn't mention the relational model or use relational terms or concepts.
V>Дык, пора бы знать уже, что в IT есть "физический уровень". ИМХО, прямо сейчас стоит закруглить насчет БД и сделать gosub на "абстракции". Иначе разговор ни о чем. V>>>Index scan — это по прежнему операция ограничения из РА, а bookmark lookup — один из видов того самого соединения. S>>Нет.
V>Достойный аргумент. Ничего если я предположу отсутствие навыков по операциям РА, бо эти вещи как бы аксиоматичны?
Какие вещи? Где аксиоматичны? Ну, продемонстрируйте мне, что является аргументом операции bookmark lookup, а что — её выходом. И попробуйте найти аналог этой операции
S>>Индексы не являются "декомпозицией" исходного отношения. Чтобы начать разговаривать об индексах, нам придётся перейти от абстрактного термина "отношение" к конкретному термину "таблица", и начать учитывать подробности хранения данных. Вы почитайте учебник по устройству СУБД — того же Гарсиа-Молина. Оптимизатор "видит" совсем другую модель, чем вы в ваших задачках по РИ.
V>Ес-но, только что мне мешает видеть ту же самую модель, что и оптимизатор? Как я тогда буду писать эффективные приложения для СУБД, если я не понимаю показания плана оптимизатора? Или вот я разработчик СУБД, с какой радости я не могу прикладывать РА к индексам? Это откуда такие запреты-то? Я не только могу, но я обязан использовать весь этот аппарат, чтобы не породить УГ.
Оттуда, что операции РА имеют ограничения. Читайте учебник по РА. Если вы разработчик СУБД, то вам придётся пользоваться несколько более другой моделью. Она будет отличаться от РА примерно так же, как ТФКП от школьной арифметики.
V>Ну ты бы по классике прошелся. Нет никаких прыжков, есть постановка задачи, анализ, и предложенная модель для решения этого класса задач. И оставь в покое несчастный SQL, это уже какое свербение в одном месте. Во многих учебниках никакого SQL нет, поэтому заканчивай делать вид, что ты видел учебники в глаза кроме руководств к конкретным СУБД.
Ну давайте, приведите мне ссылку на этот учебник, в котором никакого SQL нет.
Вот, смотрим на http://www.mstu.edu.ru/study/materials/zelenkov/toc.html. Что мы тут видим? Ога, в разделе 4 мы видим:
4.4. Реляционная алгебра
4.5. Реляционное исчисление
4.6. Язык SQL
Никакого рассказа про то, каким образом СУБД собирается исполнять SQL, который весьма отдалённо связан с РА и РИ нету.
Это я молчу про килотонны пособий вроде http://progbook.net/bd/
V>Да правильно представляю. Исходники смотрел в свое время. Более одной БД. Представляю как есть, хоть и похоже, не так, как это представляешь себе ты. V>Угу, 2, только не таких как у тебя. Ты статическое и динамическое описание модели разнес по разным уровням абстракций, мои поздравления.
Не понял, это вы кого комментируете? В моём посте не было ничего про разделение статики и динамики на 2 уровня.
V>Меня аж плющит, когда ты снова и снова сравниваешь SQL с реляционной моделью. Сравнивать язык и модель — ну это просто за рамками здравого смысла.
Это ничего, пробелы в вашем образовании можно восполнить. Вот у нас язык SQL. Он задаёт некоторые операции. Вопрос: операции над чем?
Очевидно, что существуют некоторые объекты (в смысле математики, а не ООП), которыми манипулирует SQL. Почитайте раздел 4 стандарта — там вводится довольно подробное и точное описание того, что такое "таблица", что такое "представление", что такое "процедура". И вот эта модель, что характерно, отличается от Реляционной Модели.
V>И? Реляционная модель никак не ограничивает область значений доменов. Она ими даже не интересуется. Если некая область хочет включить NULL, Nil, папу_римского — да ради бога. Насчет трехзначной логики аналогично — бредятина. По предикатам в в SQL (например в операции JOIN) всегда только два ветвления, т.е. предикаты приводимы булевскому значению, хоть и неявно.
Нет. Если бы "ветвлений" было только 2, как вы говорите, то вот такой запрос возвращал бы все строки из таблицы:
select id from a where id = 1
union all
select id from a where NOT (id = 1)
В реляционной алгебре — именно так. В SQL — хрен, простите, на воротник.
Иначе они не могли бы исопльзоваться как предикаты. Или ты имел ввиду, что есть операции сравнения в домене значений {true, false, NULL}? Ну и какие проблемы? Определи этот домен и операции по нему для конкретной схемы реляционной модели и вперед — конкретно реляционной модели, повторюсь, это по барабану.
Проблемы очень простые. В реляционной модели все предикаты выполняются в булевой логике.
V>Угу, в таблицах с отсутствующим первичным ключом. Разумеется, такие таблицы не могут иметь аналогов из реляционной модели, даже если в таблице нет дубликатов. И единственный доступ к данным — это тупой перебор. А раз так, т.е. раз аппарат реляционного исчисления к ним не применим, я бы эти "фишки" вообще не обсуждал... Ведь для подобных таблиц не требуются никакие теории.
При чём тут таблицы? И почему вы думаете, что для них не нужны никакие теории?
Поясняю на пальцах: Реляционная Модель замкнута относительно операций РА.
Это означает, что, скажем, оператор проекции всегда возвращает отношение.
Давайте возьмём примитивную таблицу — с первичным ключом, наличие которого вам кажется столь важным. В ней будут некоторые неключевые атрибуты (здесь и далее я пишу в терминах SQL):
create table Person(id int primary key, name varchar(max), cityId int foreign key references city(id))
Очевидно, эта таблица вполне себе укладывается в реляционную модель.
Возьмём от неё проекцию:
select cityId from Person
Чтобы эта проекция удовлетворяла требованиям реляционной модели, мы обязаны избавиться от дубликатов:
select distinct cityId from Person
Если бы SQL соответствовал РА и РМ, то distinct был бы принудительно приделан к каждому стейтменту.
А не сделано это оттого, что сие может оказаться крайне дорогостоящим удовольствием. Рассмотрим, скажем, вот такой запрос:
select cityName from city where cityId in (select cityId from Person where name like '%vdi%')
Здесь семантика запроса не зависит от того, возвращает ли вложенный запрос set или multiset. И в очень многих практических случаях — именно так. Если ограничиться проекциями, ограничениями, и соединениями, то появление дубликатов на промежуточных этапах несущественно, т.к. мы можем привести muliset к set на окончательном этапе. Форсирование ограничений на дубликаты на всех промежуточных этапах приведёт к падению производительности.
V>Тогда не существовало бы теории реляционных БД, коль она не нужна?
Я не говорю, что она не нужна. Существует же арифметика натуральных чисел, хотя реальные уравнения удобнее решать в комплексных числах. Нужно просто понимать, что чистая РА — это сознательное упрощение моделей, применяемых в реальных СУБД.
V>Я бы скорее сравнил Фурье и корреляцию по сетке частот.
А я бы не стал.
V>Для реляционной модели это неважно. Повторюсь, в РА важна последовательность операций, никакая конкуренция не рассматривается.
Поскольку в РА нет изменяемого состояния, конкуренция в ней вообще не интересна.
V>Я пока еще не вижу противоречий с примитивами РА.
А зачем вам противоречие? Мы же не опровергаем РА как таковую. Мы говорим о том, что РА недостаточно для описания реальных промышленных СУБД. Ситуация опять такая же, как в арифметике vs ТФКП. Я вам толкую о том, что уравнений типа f(x) = g^2(x) нужны комплексные числа, а вы мне "я не вижу противоречий c примитивами арифметики".
V>Да нету никаких индексов на физическом уровне просто. Индексы — это тоже логическая единица модели конкретной СУБД.
Вы просто не понимаете общепринятой терминологии. Есть устоявшееся сочетание "физический план выполнения запроса".
V>Ничего личного, но споры относительно РА я бы предпочел вести в терминах самой РА, взаимоотношения операций, разбора конкретных типовых задач из области РА и т.д., а не путем перестрелки с помощью выхваченных из контекста фраз "из интернета".
Непонятно, о чём именно вы хотите спорить. У нас относительно РА никакого спора нет. Весь спор — о том, что в реальных СУБД работает не РА, и что SQL — это не РА, и не РИ.
V>Я могу еще повторить больими буквами, если не понял — РА всегда оперирует неким последовательным алгоритмом.
Вы определение "императивного программирования" уже прочитали? Тогда осталось его понять. V>В общем, опять и снова могу лишь рекомендовать прорешать задачи по РА, с целью проникнуться проблематикой, и чтобы составить затем свое мнение не на вырезанных из контекста фразах, а на личном опыте.
Какие, например, задачи?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vdimas, Вы писали: V>Таки не надо смещать акценты, речь шла конкретно про профайлер. Даже если мы "тупо" замеряем "самый верхний цикл" и видим, что оптимизация некоего куска не приносит бенефитов, с чего бы тратить на него месяц?
Речь шла о том, что кое-кто тут считает, что без полного понимания внутреннего устройства потрошков машины, разработчик якобы обречён запускать профайлер каждые 10 строк.
Из этого подразумевается что
а) профайлер — это очень плохо
б) программист зачем-то заморочен задачами перформанса постоянно (а не в тот момент, когда есть что померить)
в) что программист должен быть способен решать проблемы производительности в уме
г) и вот что для этого необходимо знать матчасть назубок.
Самое смешное, что даже если удастся доказать универсальную истину пунктов а, б, и в (что, очевидно, бесперспективное занятие), и аргументировать таким образом г), ни к чему интересному мы не придём.
В том смысле, что я не делал утверждения, которое вы пытаетесь опровергнуть. Я совершенно не против знания программистом матчасти.
Я против того, чтобы программист слеплял в голове всё в сплошной монолит. Примеры приводить не буду, чтобы не спровоцировать ещё один поток "откровений" на общеизвестные темы.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, gandjustas, Вы писали:
V>>>>Это верно в той области ПО, для которой эффективность не является конкурентным преимуществом. Например, для заказного ПО, там же никакой конкуренции... Нужна лишь некая "достаточная" производительность. G>>>Да-да-да. Забавная байка. У тебя есть сведения о корреляции производительности и продаж для определенного класса программ? V>>Есть. G>Показывай.
А тебе ключи от сейфа не надо? Упрись, там и разберёшься, что на что влияет. Просто прими как факт, что есть такие предметные области, где 30 микросекунд latency — "слив зощитан", а 1,5 микросекунды — топ продаж. Но вообще, тебе о том знать не надобно, так оно проще: я ничего не имею против того, чтобы абсолютное большинство озабочивалось latency, когда оно превысит сотни миллисекунд.
V>>>>А в коробочном ПО в реальности бывает так, что профайлер показывает до 30% затрат на всего одну из самых затратных операций, но она никак не оптимизируема, всё, упёрлись в предел. Зато остальное можно подтянуть, то самое, которое 1-2% каждое в среднем, но примерно вдвое общую эффективность поднять, подняв каждую из мелочей многократно. Это из реальной практики... Для каждого такого случая нужны банально идеи, бо показания профайлера тебе код не напишут. G>>>А ты вообще прочитал то что я процитировал? В 5 пункте fixable слово видел? V>>И? G>Прочитай еще раз
If you did not meet your goal, use tools to discover what the worst-performing fixable thing is, and fix it.
"Если у вас что-то работает плохо — поправьте, что получится (именно так надо переводить fixable), используя подходящие средства." Бу-га-га! Офигительной глубины совет.
V>>>>Есть еще момент: эффективность не всегда определяется пропускной способностью, зачастую идет требования минимизации latency (у нас по работе, например), а в этом деле, когда речь идет о единицах микросекунд, профайлерами уже и близко не пахнет. G>>>А чем пахнет? ты ведь как-то меряешь этот самый latency или ты по коду пытаешься его угадать? V>>Специальные тесты на производительность нужны, с максимальной изоляцией, чтобы минимизировать паразитную постоянную составляющую измерений. G>То есть ты все равно меряешь.
Замеры замерам рознь. Я тебя уверяю, цифры, которые выдаёт профайлер в синтетических тестах, далеко не всегда подходят для выводов о производительности в реальных условиях.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, gandjustas, Вы писали:
ГВ>>А тебе ключи от сейфа не надо? Упрись, там и разберёшься, что на что влияет. Просто прими как факт, что есть такие предметные области, где 30 микросекунд latency — "слив зощитан", а 1,5 микросекунды — топ продаж. Но вообще, тебе о том знать не надобно, так оно проще: я ничего не имею против того, чтобы абсолютное большинство озабочивалось latency, когда оно превысит сотни миллисекунд.
G>Не думаю что слово "коробочный" к такому ПО применимо.
Что тут сказать? Нельзя спорить с негативно сформулированными тезисами, тем более, если они оформлены как личное мнение.
G>>>>>А ты вообще прочитал то что я процитировал? В 5 пункте fixable слово видел? V>>>>И? G>>>Прочитай еще раз
ГВ>>
If you did not meet your goal, use tools to discover what the worst-performing fixable thing is, and fix it.
ГВ>>"Если у вас что-то работает плохо — поправьте, что получится (именно так надо переводить fixable), используя подходящие средства." Бу-га-га! Офигительной глубины совет. G>И он, сука, работает. Я тут недавно консультировал коллег по вопросам производительности. Они полмесяца тыкались не зная в чем проблема, потом я показал как в их случае надо мерить. Вот померили и сразу нашлись узкие места. Которые поправили за считанные дни.
Молодцы. Только это никак не отменяет того, что приведённая цитата содержит банальность.
G>Любая попытка улучшить производительность должна начинаться с замеров и устранения узких мест. G>Тут же каждый второй гуру говорит что нужны тайные знания, а на практике 99% производительности вытягивается именно так. А только 1% требует "щаманства".
Как ты, наверное, понимаешь, "99%" — это уже не усиление высказывания, а маркер. Сказать, маркер чего именно?
ГВ>>Замеры замерам рознь. Я тебя уверяю, цифры, которые выдаёт профайлер в синтетических тестах, далеко не всегда подходят для выводов о производительности в реальных условиях. G>Отсутствие каких-либо цифр не лучше. Попытка делать хоть какие-то выводы в таком случае — шаманство.
Никто не спорит с тем, что цифры полезны. Вопрос в том, как их получить и как потом применить. В случае серьёзных требований к производительности и то, и другое может оказаться весьма нетривиальными задачами.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, vdimas, Вы писали: V>>Таки не надо смещать акценты, речь шла конкретно про профайлер. Даже если мы "тупо" замеряем "самый верхний цикл" и видим, что оптимизация некоего куска не приносит бенефитов, с чего бы тратить на него месяц? S>Речь шла о том, что кое-кто тут считает, что без полного понимания внутреннего устройства потрошков машины, разработчик якобы обречён запускать профайлер каждые 10 строк.
Что есть "потрошки машины"? Конкретная архитектура, что ли? Зачем? Достаточно владеть классом архитектур, например Гарвардской или Фон Неймана, знать про особенности: суперскаляр, явный параллелизм или еще какой-нить гипер-трединг. Такие вещи конечно знать стоит.
S>разработчик якобы обречён запускать профайлер каждые 10 строк.
Пример Липперта как раз взят из этой области. Был приведен код, который никогда не породит более-менее опытный разработчик. Показана "польза" профайлера на примере полнейшего УГ.
S>Из этого подразумевается что S>а) профайлер — это очень плохо
Каждые 10 строк? Хуже некуда. Все еще не согласен? Или будешь делать попытки обобщить на "плохо в любом случае"? Будет демагогия.
S>б) программист зачем-то заморочен задачами перформанса постоянно (а не в тот момент, когда есть что померить)
Я не понимаю степень негатива термина "заморочен"... Уметь делать хотя бы грубые прикидки характеристик собственных разрабатываемых алгоритмов разработчик обязан, разумеется. Если он этого не умеет и не хочет уметь, пусть развивается, например в специалиста некоей прикладной области или менеджмент.
S>в) что программист должен быть способен решать проблемы производительности в уме
В терминах O(n) — непременно. А так же иметь некий опыт прикидки коэф К при O(n) для самых частоиспользуемых конструкций.
S>г) и вот что для этого необходимо знать матчасть назубок.
S>Самое смешное, что даже если удастся доказать универсальную истину пунктов а, б, и в (что, очевидно, бесперспективное занятие), и аргументировать таким образом г), ни к чему интересному мы не придём.
А я его и не понял, пункта г. В дисциплине IT матчасть столь широка, что стоило бы сузить. Универсальный подход тут один — надо разбираться в том, над чем работаешь. Т.е. и в прикладной области и в областях общеайтишных, применяемых для решения прикладной задачи.
S>В том смысле, что я не делал утверждения, которое вы пытаетесь опровергнуть. Я совершенно не против знания программистом матчасти. S>Я против того, чтобы программист слеплял в голове всё в сплошной монолит.
Я понятия не имею, какие конкретно образы принимают разделы наук, инженерии и связей м/у ними в твоей голове. Боюсь, что это разговоры в пользу бедных.
S>Примеры приводить не буду, чтобы не спровоцировать ещё один поток "откровений" на общеизвестные темы.
А не уедешь далеко на примерах с манерой додумывать за оппонента. Ведь у тебя любой пример в стиле: "вы наверно считаете так-то, но вот вам пример, где вы ошибаетесь..." Такой стиль малость утомляет, когда уже не в первый раз. Я с самого начала предложил таки просто договориться о термине "абстракция", чтобы быть уверенным, что мы говорим об одном и том же. Заодно сэкономить массу времени. А не упражняться примерами на образное мышление. Хотя и это путь, хоть один из самых долгих... В итоге, я кажется понял, что для тебя есть абстракция, попытаюсь сформулировать, коль ты согласен обсуждать что угодно, кроме посылов, за которые зацепились. Из твоих постов во всей этой ветке мне начинает казаться, что абстракции для тебя — это нечто многослойное, навроде луковицы, типа внутренних и внешних интерфейсов какого-нить АПИ. Наверно отсюда эти попытки выстроить некую однонаправленную (подчиненную) зависимость м/у понятиями, так? Дык, можно было тогда бодаться столь же безрезультатно еще год...
Абстракция — это упрощение, модель, и ничего более. Упрощение в каждом конкретном случае должно быть максимальным, в этом суть абстракции. Это именно то, что я имел ввиду под "разные абстракции для разных по характеру работ над одним и тем же кодом". Еще раз, абстракция — это никакой не "слой" и не "уровень". Потому как "слой" и "уровень" в ПО обозначает именно эти слова, и служат для разграничения подсистем и определения интерфейса м/у подсистемами. Но сами интерфейсы — не есть абстракция, это надо понимать. Абстракцией будет некая вербальная (математическая, автоматная, еще какая-нить) модель подсистемы, доступная для оперирования через те самые интефейсы. Итого, "слой" и "уровень" могут иметь описывающую их работу абстрактную модель, но могут иметь и не абстрактную, а вполне конкретную/реальную. Поэтому это не одно и то же. Подсистемы (слои, уровни, интерфейсы ПО и т.д.) могут иметь связанную с ними абстракцию, но обратное неверно, "абстракция" не значит "слой" или "уровень". Мы вводим слои, чтобы ограничить оперирование конечным числом абстракций, чтобы договориться о терминах внутри системы, т.е. поиметь некие точки отсчета. Это именно то, что я имел ввиду, под "разработчик выбирает уровни абстракции произвольно". Ты мне привел "уже заданные" уровни абстракции дотнета? Гы... разработчики в MS выбрали такие уровни в процессе разработки, сверху они ни разу не заданы.
Твой любимый пример с языком SQL — показателен. Язык — не есть сама модель СУБД, это языковое ср-во оперирования НАД моделью СУБД, считай публичный интерфейс модели. И то, далеко не полный обычно, бо многие вещи в том же MS SQL идут не в языковом, а в "библиотечном" виде через специальные системные ф-ии или запросы к системным таблицам. Т.е. не получилось выразить в конструкциях языка операции над моделью, приходится "доэмулировать" части модели уже имеющимися ср-вами языка. В дотнете, кстати, аналогично: в C# не доступны все возможности CLI, хотя такие возможности, задействованные в других языках, вполне можно раскрутить через рефлексию, т.е. через библиотечные ср-ва, но не языковые.
Здравствуйте, Sinclair, Вы писали:
V>>Опять продемагогил... спасибо... ФП не означает отсутствие императивности, оно означает наличие ф-ий как первоклассных объектов языка, только и всего. И с чего бы императивному алгоритму оперировать обязательно иммутабельным состоянием? Чай не ООП... S>Вы, наверное, хотели сказать мутабельным состоянием?
Ну да, я же возражал. Ответишь или как?
S>ОМГ. Я же подробно объяснил, что операции, выполняемые SQL сервером — совсем не те операции, которые описаны в РА.
Некоторые не совсем те, некоторые совсем те.
V>>Да, именно, удивительное противоречие самому себе. S>Никакого противоречия нет. Вы по-прежнему не можете отличить абстрактную математику от её реализации? Печально.
В каком месте ты это увидел? Давай пошагово, как ты пришел к такому выводу. Я уже плохо понимаю, что именно ты пытаешься доказать. Сорри, выглядит как потеря нити беседы... Мне немного сложно уловить саму постановку вопроса в плане "отличить". IMHO в IT всегда стоит задача ровно наоборот — найти связь некоей частной задачи с неким прикладным или фундаментальным матаппаратом, чтобы не изобретать велосипеды при решении этой задачи.
S>Ваши идеи про "скрытые атрибуты" я понял. К сожалению, они вам не помогут.
Они помогают всем, и мне и разработчикам СУБД. Оставь сожаления себе.
S>Для начала, ничего подобного в реляционной модели нет, и с точки зрения алгебры вы вводите просто тавтологии, т.е. отношения, не содержащие новой информации.
Обоснуй в терминах реляционной модели, плиз. Давай, отноешния, аттрибуты, вывод незначимости аттрибута из-за наличия таких-то зависимостей. Давай уже заканчивать разводить пустые ля-ля, ближе к телу.
S>Во-вторых, в реляционной модели нет понятия порядка, поэтому вам не удастся, оставаясь в рамках неё, рассчитать стоимость операций над отношениями.
Ну это ход конем, конечно, в реализации программы "оставаться в рамках неё"... Ничего, что у меня целые числа ограниченной разрядности, для начала?
Короче, задачи реализации примитивов РА над различными популярными видами структур идут как лабораторки у студентов, справлялись даже девочки. Тебе лично я писал о готовых формулах
вычисления стоимости для пар {объект, операция}.
Итого, есть некая операция из РА, и есть ее некая реализация некоторым объектом, к этой паре привязана стоимость операции. Буду повторять, пока не поймешь.
V>>Ну так что первично, а что вторично? Мне как разработчику видно ровно обратное, фиксированные размеры страниц нужны исключительно для нужд кластерных индексов, которые принципиально живут только в контексте детерминированных размеров. S>Вы делаете сразу несколько неверных утверждений. S>1. Кластерному индексу всё равно, ограничен размер записи или нет.
Не все равно, в БД с неизвестными размерами записей нет кластерных индексов.
S>2. Фиксированные размеры страниц нужны для унификации алгоритмов доступа и распределения памяти.
Таки речь была не о страницах. Покажи мне двоичный поиск в данных неизвестной длины.
S>Вы бредите? Seek по ключу индекса дёшев всегда, и никак не требует ограничения размеров таблицы.
По кластерному не всегда, зависит от размеров таблицы. При достаточно "широкой" таблице в несколько раз менее эффективен, чем некластерный. Я получал в 4 раза увеличение общего быстродействия. Это потому что некоторые операции стали быстрее на порядок после выноса индекса как некластерного. И про монотонность ты тоже правильно говорил, кстати, проблема с кластерными.
S>Я вам привёл подробные условия превосходства кластерного индекса над некластерным. Что именно вам непонятно?
Я не понял, где "превосходство"? Описанные признаки идут за превосходство только в ограниченных условиях.
V>>Ну оставайся при своем. S>Почему "при своём"? Я же давал ссылку: S>
S>The current ISO SQL standard doesn't mention the relational model or use relational terms or concepts.
Ну так, чтобы путанницы не возникло, непосредственного маппинга нет. Есть частично, во всех тех самых учебниках говорится. Но это частично — это те самые 99% всех операций, выборка, пеерименование, объединение, произведение/join и т.д.
V>>Достойный аргумент. Ничего если я предположу отсутствие навыков по операциям РА, бо эти вещи как бы аксиоматичны? S>Какие вещи? Где аксиоматичны? Ну, продемонстрируйте мне, что является аргументом операции bookmark lookup, а что — её выходом. И попробуйте найти аналог этой операции
Пересечение, если для мн-ва букмарков или ограничение, если по 1-му.
V>>Ес-но, только что мне мешает видеть ту же самую модель, что и оптимизатор? Как я тогда буду писать эффективные приложения для СУБД, если я не понимаю показания плана оптимизатора? Или вот я разработчик СУБД, с какой радости я не могу прикладывать РА к индексам? Это откуда такие запреты-то? Я не только могу, но я обязан использовать весь этот аппарат, чтобы не породить УГ. S>Оттуда, что операции РА имеют ограничения. Читайте учебник по РА.
Какой именно? Давай, справедливости ради работу Кодда?
Объясни на пальцах, почему я не имею права реализовывать в коде некие операции из РА? Вот я принял некую модель хранения отношений в своей программе, вот хочу реализовать над отношениями операции из РА. Где ты взял запрет? Я уже который раз не могу добиться, обоснуй, почему нельзя.
Почему я целочисленные числа могу делить, например, хотя результат будет врать, согласно математике, а реализовать несчастные примитивы РА, причем именно так, чтобы они "не врали" — не могу? Это откуда такая трава-то?
S>Если вы разработчик СУБД, то вам придётся пользоваться несколько более другой моделью. Она будет отличаться от РА примерно так же, как ТФКП от школьной арифметики.
У тебя будут некие контейнеры, которые будут предоставлять операции над ними, например операции ограничения. Воможно, что помимо этих операций будут предоставлять еще некоторые, выходящие за рамки РА. Да ради бога. У меня в программе-примочке для гитары столько кода, никак не связанного непосредственно с теорией обработки сигналов, особенно в плане нелинейных преобразований... Однако же, там где применим существующий матаппарат, ему весь остальной код ничуть не мешает.
V>>Ну ты бы по классике прошелся. Нет никаких прыжков, есть постановка задачи, анализ, и предложенная модель для решения этого класса задач. И оставь в покое несчастный SQL, это уже какое свербение в одном месте. Во многих учебниках никакого SQL нет, поэтому заканчивай делать вид, что ты видел учебники в глаза кроме руководств к конкретным СУБД. S>Ну давайте, приведите мне ссылку на этот учебник, в котором никакого SQL нет.
Коль речь именно об учебнике, то исходная работа Кодда на учебник не тянет, угу, хотя крайне рекомендуется к прочтению хотя бы однократно. Популярен вот этот учебник по теории реляционых БД: http://www.twirpx.com/file/100951/ Многие "учебные пособия" по реляционным СУБД в наших ВУЗах идут как "творческая компиляция" именно этого учебника.
Рассматривается 5 языков запросов, и среди них SQL. Дается ему характеристика.
Синтаксически SQL близок к исчислению кортежей, но не более, так как он также использует и операции реляционной алгебры.
И я к этому вопросу возвращаться больше не буду, сорри, бо надоело 5-й пост спорить со слухами. Коль оппонент так настаивает на чем-то, может оно не спроста? Может пора было уже погуглить хотя бы треть того времени, что было затрачено на написание поста?
Другим примером ранней реляционной системы является Ingres [21-22], разработанный на рубеже 70 и 80-х годов в Беркли. Эта университетская система изначально была настроена на работу в UNIX'e и не ориентировалась на фиксированную аппаратную платформу. Каждому хранимому отношению соответствовал отдельный файл. Индексы являлись частным случаем отношений.
Как известно, двумя фундаментальными языками запросов к реляционным БД являютсяязыки реляционной алгебры и реляционного исчисления. При всей своей строгости итеоретической обоснованности эти языки редко используются в современных реляционных СУБД в качестве средств пользовательского интерфейса. Запросы на этихязыках трудно формулировать и понимать. SQL представляет собой некоторуюкомбинацию реляционного исчисления кортежей и реляционной алгебры, причем до сихпор нет общего согласия, к какому из классических языков он ближе. При этомвозможности SQL шире, чем у этих базовых реляционных языков, в частности, в общемслучае невозможна трансляция запроса, сформулированного на SQL, в выражение реляционной алгебры, требуется некоторое ее расширение.
От себя добавлю, что для подавляющего большинства обычных запросов, "без выкрутасов" конкретной СУБД, никакого расширения не требуется.
В общем, учебник дан, в конце каждого раздела задачи. Приятного времяпрепровождения. Особенно полезен обзор других языков, помимо SQL, чтобы убрать из головы на нем некий специальный фокус и навести порядок в плане понимания самой проблематики языков запросов.
Типа, SQL за 21 день? Или "самое полное руководство по MS SQL Server"? Спасибо за понимание.
V>>Меня аж плющит, когда ты снова и снова сравниваешь SQL с реляционной моделью. Сравнивать язык и модель — ну это просто за рамками здравого смысла. S>Это ничего, пробелы в вашем образовании можно восполнить. Вот у нас язык SQL. Он задаёт некоторые операции. Вопрос: операции над чем?
S>Очевидно, что существуют некоторые объекты (в смысле математики, а не ООП), которыми манипулирует SQL. Почитайте раздел 4 стандарта — там вводится довольно подробное и точное описание того, что такое "таблица", что такое "представление", что такое "процедура". И вот эта модель, что характерно, отличается от Реляционной Модели.
Таки общепринято считать за соответствие таблицы и отношения, например. А уж представления — тем более.
S>В реляционной алгебре — именно так. В SQL — хрен, простите, на воротник.
Т.е. что есть "домен" мы тоже в упор не понимаем? Тогда на пальцах: ты показал домен {true, false, null}, с некоторыми правилами/формулами над значениями доменов, например not(null)=null. Значение из этого домена при использовании в кач-ве предиката неявно приводится к двоичной логике. При чем, далеко не во всех субд. Правила приведения этого домена к значению предиката указан в справочнике конкретной СУБД, но не в справочнике к стандарту SQL. Поэтому грамотно было бы сказать не в SQL, а в MS Transact SQL. Даже в этом случае нет проблем. А у тебя проблема от того, что ты предполагаешь, будто предикат может иметь более двух значений. Не может по определению. Если значение выражения не приводимо к булевскому, выдается ошибка. В твоем примере на null некоторые базы ругнуться в рантайм, и тебе потребуется привести преобразование null к boolean явно через конструкции is null, is not null.
S>Иначе они не могли бы исопльзоваться как предикаты. Или ты имел ввиду, что есть операции сравнения в домене значений {true, false, NULL}? Ну и какие проблемы? Определи этот домен и операции по нему для конкретной схемы реляционной модели и вперед — конкретно реляционной модели, повторюсь, это по барабану.
S>Проблемы очень простые. В реляционной модели все предикаты выполняются в булевой логике.
Выделенное — несвязанный набор слов.
S>Это означает, что, скажем, оператор проекции всегда возвращает отношение. S>Давайте возьмём примитивную таблицу — с первичным ключом, наличие которого вам кажется столь важным. В ней будут некоторые неключевые атрибуты (здесь и далее я пишу в терминах SQL): S>
S>create table Person(id int primary key, name varchar(max), cityId int foreign key references city(id))
S>
S>Очевидно, эта таблица вполне себе укладывается в реляционную модель. S>Возьмём от неё проекцию: S>
S>select cityId from Person
S>
S>Чтобы эта проекция удовлетворяла требованиям реляционной модели, мы обязаны избавиться от дубликатов: S>
S>select distinct cityId from Person
S>
S>Если бы SQL соответствовал РА и РМ, то distinct был бы принудительно приделан к каждому стейтменту.
Боже, какие спекуляции. А для операции объединения наоборот, чтобы не было distinct надо специально указать ALL. Я лишь вижу, что для обоих случаев существует языковый способ выполнить строгую операцию РА, либо с практически тем же синтаксисом рассматривать набор данных, который не подчиняется в дальнейшем реляционной теории. То, что SQL позволяет больше, чем РА, никто и не пытался оспаривать.
Характерно, что обсуждение это (ты просто забыл уже) выросло из обсуждения операций над букмарками индексов, которые таки именно что уникальны и полностью удовлетворяют матаппарату РА. А вопрос вообще изначально стоял так: если в каком-то месте матаппарат подходящ, почему он не должен использоваться?
S>А не сделано это оттого, что сие может оказаться крайне дорогостоящим удовольствием.
Красиво ты поспешил с выводами... ведь это смотря какой результат будет формирован в конце, зачастую ровно наоборот: distinc "где-то в середине" способен поднять эффективность многократно.
S>
S>select cityName from city where cityId in (select cityId from Person where name like '%vdi%')
S>
S>Здесь семантика запроса не зависит от того, возвращает ли вложенный запрос set или multiset. И в очень многих практических случаях — именно так. Если ограничиться проекциями, ограничениями, и соединениями, то появление дубликатов на промежуточных этапах несущественно, т.к. мы можем привести muliset к set на окончательном этапе. Форсирование ограничений на дубликаты на всех промежуточных этапах приведёт к падению производительности.
Настаиваю, что ты поторопился с выводами. По моему опыту "вылизывания" быстродействия запросов, ровно наоборот — приходится расставлять disctinct направо и налево, и чем раньше в "сложной" формуле, тем заметнее эффект.
V>>Тогда не существовало бы теории реляционных БД, коль она не нужна? S>Я не говорю, что она не нужна. Существует же арифметика натуральных чисел, хотя реальные уравнения удобнее решать в комплексных числах. Нужно просто понимать, что чистая РА — это сознательное упрощение моделей, применяемых в реальных СУБД.
Тогда для чего оно надо? (есть тут смайлик печальной улыбки?)
V>>Я бы скорее сравнил Фурье и корреляцию по сетке частот. S>А я бы не стал.
Почему?
V>>Для реляционной модели это неважно. Повторюсь, в РА важна последовательность операций, никакая конкуренция не рассматривается. S>Поскольку в РА нет изменяемого состояния, конкуренция в ней вообще не интересна.
Операции обновления отношений относятся к операциям над кортежами, а все вместе входит в теорию реляционных СУБД, матаппарат которой мы и рассматриваем. Например, декомпозиция отношений называется "оператор фактор" и не входит в РА, хоть в ходит все в тот же аппарат теории реляционных БД. Я даже скажу, что без этого оператора в реляционной теории просто жизни нет, ведь мы даже не сможем привести исходную схему к нормальным формам. Эта операция не входит в РА потому, что результатом операции является множество отношений, а не одно, как приняно для всех остальных операций из РА. Но, тем не менее эта операция входит в теорию реляционных БД и
используется как концептуальное ср-во для поиска эффективных путей хранения отношения
Помнишь, что я тебе про индексы и декомпозицию отношений говорил? Это все не с потолка берется и не из головы каждого нового разработчика, а давно пережеванные в рамках реляционой теории вещи. Избыточность, покрытие, ограничения целостности, нормальные формы, — вот пример целей, задаваемых реляционной теории, а РА — лишь один из инструментов.
S>А зачем вам противоречие? Мы же не опровергаем РА как таковую. Мы говорим о том, что РА недостаточно для описания реальных промышленных СУБД.
А реляционного исчисления? А всех наработок реляционной теории БД?
Это уже похоже на метания.
S>Ситуация опять такая же, как в арифметике vs ТФКП. Я вам толкую о том, что уравнений типа f(x) = g^2(x) нужны комплексные числа, а вы мне "я не вижу противоречий c примитивами арифметики".
Э, нет. Ты мне о том, что эти комплексные числа нужно изобрести каждый раз заново, а я тебе — так вот же, учебник по вышке.
V>>Да нету никаких индексов на физическом уровне просто. Индексы — это тоже логическая единица модели конкретной СУБД. S>Вы просто не понимаете общепринятой терминологии. Есть устоявшееся сочетание "физический план выполнения запроса".
Вот этот термин и надо было применять.
V>>Я могу еще повторить больими буквами, если не понял — РА всегда оперирует неким последовательным алгоритмом. S>Вы определение "императивного программирования" уже прочитали? Тогда осталось его понять.
Можно я избавлю себя от поиска соответствия "последовательного алгоритма" и "императивного программирования"? Важно только одно — аргументами последующих операций являются результаты предыдущих. Это позволяет утверждать, что порядок вычислений важен.
V>>В общем, опять и снова могу лишь рекомендовать прорешать задачи по РА, с целью проникнуться проблематикой, и чтобы составить затем свое мнение не на вырезанных из контекста фразах, а на личном опыте. S>Какие, например, задачи?
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
G>>Отсутствие каких-либо цифр не лучше. Попытка делать хоть какие-то выводы в таком случае — шаманство.
V>А где ты видел "отсутствие каких-либо цифр"? Речь шла зашла о сценариях применения профайлеров. В любом случае дотнетный профайлер не поможет, когда доходит до уровня игр с разной грануляцией блокировок, переделкой алгоритмов в многопоточные или обратно и т.д., борьбой с издержкой кешей, затрат на переключения контекстов и т.д. Тут уместны уже нейтивные от интел или амд для нейтивных же программ.
Не надо усложнять. Ты говорил что надо уметь "видеть" проблемы быстродействия в коде, тебе дали элементарный код, но ты в нем проблему не увидел.
Как ты собираешься в сложных случаях без измерений вообще что-то делать?
Ты выдвигал тезис о том что априори важно понимать как работает тот или иной код с точки зрения быстродействия. Тебе уже не один человек говорит что это необязательное условие, что в первую очередь надо мерить.
Здравствуйте, vdimas, Вы писали: V>Ну да, я же возражал. Ответишь или как?
Я же ответил. У вас трудности с восприятием?
Повторю: Ну, как бы по определению:
In computer science, imperative programming is a programming paradigm that describes computation in terms of statements that change a program state
V>Некоторые не совсем те, некоторые совсем те.
Даже если бы были те, которые "совсем те", важно то, что есть "совсем не те".
V>В каком месте ты это увидел? Давай пошагово, как ты пришел к такому выводу.
Перечитайте текст, на который вы отвечаете, ещё раз. Есть три фразы:
С точки зрения математики комплексных чисел, операция умножения a * b не имеет никакой "стоимости".
А вот если мы перейдём к некоторому представлению комплексных чисел в компьютере, то операция a * b будет иметь некоторую реализацию в этом представлении.
И вот уже у этой реализации будет некоторая стоимость, выраженная в терминах более низкоуровневых операций.
Вы в ответ на мою первую возражаете моей же третьей, а потом внезапно обнаруживаете "противоречие". Рекомендую прекратить принимать то, что вы принимаете, что бы это ни было.
V>Обоснуй в терминах реляционной модели, плиз. Давай, отноешния, аттрибуты, вывод незначимости аттрибута из-за наличия таких-то зависимостей. Давай уже заканчивать разводить пустые ля-ля, ближе к телу.
А куда ближе? Возьмём ваш собственный пример (надеюсь, с его пониманием у вас проблем не будет?):
Простейший пример: есть некая схема R {ABCD}, и заданы зависимости A->B, B->CD. Для этой схемы будет уместна декомпозиция {AB, BCD}, причем, в реальной СУБД мы во втором отношении можем создать индекс B, сугубо эффективности ради, но! это будет означать лишь еще раз произвести декомпозицию по всем правилам декомпозиций с вводом специального аттрибута-ключа B#, для требований сохранения исходной зависимости B->CD транзитивно через B->B#, B#->CD. В итоге получим декомпозицию заданной схемы в виде: {AB, BB#, B#CD}.
Вот вы ввели отношение BB#. Зачем оно? Оно не привносит никакой новой информации. Потому что у нас B<->B#.
V>Ну это ход конем, конечно, в реализации программы "оставаться в рамках неё"... Ничего, что у меня целые числа ограниченной разрядности, для начала?
Ну, вообще говоря, это надо учитывать. А вы не знали? Соотношения, справедливые для "абстрактной арифметики целых чисел" могут запросто потерять справедливость для "арифметики чисел по модулю 2^32". Если вам это не очевидно, то не стесняйтесь спрашивать.
V>Итого, есть некая операция из РА, и есть ее некая реализация некоторым объектом, к этой паре привязана стоимость операции. Буду повторять, пока не поймешь.
Вы продолжаете меня развлекать. Можно привести пример такой "пары"? Ну, чисто чтобы я понял, что вы считаете стоимостью, а что — операцией.
V>Не все равно, в БД с неизвестными размерами записей нет кластерных индексов.
Скажите, где вы это вычитали? Вот, например, в MS SQL 2008 ограничение на размер записей снято. Кластерные индексы, тем не менее, существуют. V>Таки речь была не о страницах.
А о чём? Я же вам пишу: ограничения на размер записи (8060 байт) были связаны с ограниченностью размера страницы (8192 байта). Наличие либо отстутсвие кластерного индекса никак не влияет на это ограничение. V>Покажи мне двоичный поиск в данных неизвестной длины.
Ничего не понимаю. В чём ваша проблема? Вы считаете, что невозможно построить индекс по ключу неограниченной длины?
Во-первых, это не так. Во-вторых, если бы даже это было так, то какая разница, кластерный индекс или нет?
В-третьих, мы обсуждали размер данных, а не размер ключа.
V>По кластерному не всегда, зависит от размеров таблицы. При достаточно "широкой" таблице в несколько раз менее эффективен, чем некластерный.
Теперь пошла в ход "ширина" таблицы. Вы мне лучше расскажите, при чём тут вмещаемость таблицы в оперативную память, которую вы упоминали в прошлый раз.
V>Я не понял, где "превосходство"? Описанные признаки идут за превосходство только в ограниченных условиях.
Совершенно верно. А вы как ожидали? Что кластерный индекс будет панацеей?
S>>Какие вещи? Где аксиоматичны? Ну, продемонстрируйте мне, что является аргументом операции bookmark lookup, а что — её выходом. И попробуйте найти аналог этой операции V>Пересечение, если для мн-ва букмарков или ограничение, если по 1-му.
Перечитайте вопрос ещё раз и постарайтесь ответить на него полностью.
V>Какой именно? Давай, справедливости ради работу Кодда? V>Объясни на пальцах, почему я не имею права реализовывать в коде некие операции из РА? Вот я принял некую модель хранения отношений в своей программе, вот хочу реализовать над отношениями операции из РА. Где ты взял запрет? Я уже который раз не могу добиться, обоснуй, почему нельзя.
Да лично вам-то я не запрещаю. Были, были попытки построить СУБД на основе "чистой" реляционной модели. В промышленность не пошли. Читайте RTFM. А реальные СУБД уже реализованы так, как они реализованы. А не так, как вы себе представляете.
V>
V>Как известно, двумя фундаментальными языками запросов к реляционным БД являютсяязыки реляционной алгебры и реляционного исчисления. При всей своей строгости итеоретической обоснованности эти языки редко используются в современных реляционных СУБД в качестве средств пользовательского интерфейса. Запросы на этихязыках трудно формулировать и понимать. SQL представляет собой некоторуюкомбинацию реляционного исчисления кортежей и реляционной алгебры, причем до сихпор нет общего согласия, к какому из классических языков он ближе. При этомвозможности SQL шире, чем у этих базовых реляционных языков, в частности, в общемслучае невозможна трансляция запроса, сформулированного на SQL, в выражение реляционной алгебры, требуется некоторое ее расширение.
Прекрасно. Вы нашли-таки аргумент в пользу моей правоты.
V>От себя добавлю, что для подавляющего большинства обычных запросов, "без выкрутасов" конкретной СУБД, никакого расширения не требуется.
А я от себя добавлю, что нет, для подавляющего большинства обычных запросов, "без выкрутасов", и без конкретной СУБД, таки требуется расширение.
V>Таки над конкретной БД, чаще всего не предоставляя всех ср-в по оперированию ей, при этом.
Да? А ISO SQL — он над какой конкретной БД?
V>Таки общепринято считать за соответствие таблицы и отношения, например.
Таки это распространённое заблуждение. Я же вам подробно объяснил, почему.
V>Т.е. что есть "домен" мы тоже в упор не понимаем? Тогда на пальцах: ты показал домен {true, false, null}, с некоторыми правилами/формулами над значениями доменов, например not(null)=null. Значение из этого домена при использовании в кач-ве предиката неявно приводится к двоичной логике.
Нет. С чего это вы взяли? V>При чем, далеко не во всех субд. Правила приведения этого домена к значению предиката указан в справочнике конкретной СУБД, но не в справочнике к стандарту SQL.
Вы сами-то стандарт читали? http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt
Курить раздел 8 до просветления. Подробнейшим образом изложены формальные правила исчисления предикатов в SQL. И таки да, предикат возвращает одно из трёх значений. Никакого приведения к двоичной логике нет — оно у вас в голове.
V>Поэтому грамотно было бы сказать не в SQL, а в MS Transact SQL. Даже в этом случае нет проблем. А у тебя проблема от того, что ты предполагаешь, будто предикат может иметь более двух значений. Не может по определению. Если значение выражения не приводимо к булевскому, выдается ошибка. В твоем примере на null некоторые базы ругнуться в рантайм, и тебе потребуется привести преобразование null к boolean явно через конструкции is null, is not null.
Вы бредите. Никакой ошибки не выдаётся (если, конечно, СУБД соответствует стандарту). Выдаётся результат, который не соответствует результату в РА.
S>>Иначе они не могли бы исопльзоваться как предикаты. Или ты имел ввиду, что есть операции сравнения в домене значений {true, false, NULL}? Ну и какие проблемы? Определи этот домен и операции по нему для конкретной схемы реляционной модели и вперед — конкретно реляционной модели, повторюсь, это по барабану.
Я вам показал, какие проблемы возникают в реляционной модели.
V>Боже, какие спекуляции. А для операции объединения наоборот, чтобы не было distinct надо специально указать ALL. Я лишь вижу, что для обоих случаев существует языковый способ выполнить строгую операцию РА, либо с практически тем же синтаксисом рассматривать набор данных, который не подчиняется в дальнейшем реляционной теории.
Совершенно верно. И большая часть реальных баз данных "не подчиняется в дальнейшем реляционной теории". V>То, что SQL позволяет больше, чем РА, никто и не пытался оспаривать.
А, ну уже некий прогресс. Пару постов назад вы просто рубаху на груди рвали по поводу того, что ничего кроме РА в SQL нету.
V>Характерно, что обсуждение это (ты просто забыл уже) выросло из обсуждения операций над букмарками индексов, которые таки именно что уникальны и полностью удовлетворяют матаппарату РА.
Обсуждение выросло из способности программиста отличать особенности конкретной СУБД от ISO SQL, а его — от реляционной модели.
V>Красиво ты поспешил с выводами... ведь это смотря какой результат будет формирован в конце, зачастую ровно наоборот: distinc "где-то в середине" способен поднять эффективность многократно.
Я не поспешил, это вы спешите с интерпретацией. Мало ли что "зачастую". Вопрос в том — сколько будет случаев, где производительность просядет? Именно из-за них выбор, работать ли с множествами или с мультимножествами, отдан программисту. "Чистая" РМ оказалась нежизнеспособной на практике.
V>Настаиваю, что ты поторопился с выводами. По моему опыту "вылизывания" быстродействия запросов, ровно наоборот — приходится расставлять disctinct направо и налево, и чем раньше в "сложной" формуле, тем заметнее эффект.
С учётом ваших перлов относительно кластерных индексов, я не стану принимать вашу настойчивость во внимание.
V>Тогда для чего оно надо? (есть тут смайлик печальной улыбки?)
Как основа для более реальных теорий. Релятивистская механика точнее ньютоновской, но это не означает, что ньютоновскую не нужно изучать.
V>Операции обновления отношений относятся к операциям над кортежами, а все вместе входит в теорию реляционных СУБД, матаппарат которой мы и рассматриваем. Например, декомпозиция отношений называется "оператор фактор" и не входит в РА, хоть в ходит все в тот же аппарат теории реляционных БД. Я даже скажу, что без этого оператора в реляционной теории просто жизни нет, ведь мы даже не сможем привести исходную схему к нормальным формам.
Эта операция не входит в РА потому, что результатом операции является множество отношений, а не одно, как приняно для всех остальных операций из РА. Но, тем не менее эта операция входит в теорию реляционных БД и V>
V>используется как концептуальное ср-во для поиска эффективных путей хранения отношения
Я не очень понимаю, о какой именно реляционной теории вы ведёте речь. Вы не могли бы дать какую-нибудь ссылку на эту теорию?
Впрочем, у меня складывается впечатление, что оператор, о котором вы говорите, можно формально определить через те же операторы РА, которые ввёл Кодд.
V>Помнишь, что я тебе про индексы и декомпозицию отношений говорил? Это все не с потолка берется и не из головы каждого нового разработчика, а давно пережеванные в рамках реляционой теории вещи. Избыточность, покрытие, ограничения целостности, нормальные формы, — вот пример целей, задаваемых реляционной теории, а РА — лишь один из инструментов.
Ок, очень хорошо. Дайте, пожалуйста, ссылку на определение термина "реляционная теория", чтобы мы говорили об одном и том же.
V>А реляционного исчисления? А всех наработок реляционной теории БД? Всех теоретических наработок — достаточно. Я просто настаиваю на том, чтобы отделять мух от котлет.
А то у вас в голове, скажем, понятие "кластерный индекс" неразрывно связано с какими-то идиотскими ограничениями (которые, если и имели место, то в какой-то конкретной реализации этого понятия).
V>Э, нет. Ты мне о том, что эти комплексные числа нужно изобрести каждый раз заново, а я тебе — так вот же, учебник по вышке.
Где вы нашли у меня такое утверждение?
V>Вот этот термин и надо было применять.
Я его и применяю.
V>Можно я избавлю себя от поиска соответствия "последовательного алгоритма" и "императивного программирования"?
Нет, нельзя. Это же вы пытаетесь применять их как синонимы:
Короче, преобразования данных, выполняемых в терминах РА — это ВСЕГДА императивный алгоритм
Так что будьте любезны применять термины в соответствии с их назначением.
V>Важно только одно — аргументами последующих операций являются результаты предыдущих. Это позволяет утверждать, что порядок вычислений важен.
Нет, это не позволяет такого утверждать. Поймите, в РА нет никаких "вычислений". Есть декларации того, как "выход" операции связан со "входом". РА не обязывает исполнителя реально "просматривать" кортежи при выполнении этих операций. РА не обязывает исполнителя формировать промежуточные результаты в сколь бы то ни было воспринимаемом виде. Понимаете?
Я имею право как угодно переупорядочивать операции, если семантика сохраняется. И есть даже специальные соотношения эквивалентности, которые помогают мне это делать. Похожие соотношения эквивалентности применяет оптимизатор запросов на этапе построение логического плана исполнения.
Граница между императивным и декларативным — она именно в наличии изменяемого состояния. Если вам это непонятно, не стесняйтесь спрашивать.
V>А в конце каждой главы по ссылке.
ОМГ. Знаете, я в аспирантуре занимался разработкой своей собственной СУБД. А "задачек из РА" в применении к реальным проектам выполнил столько, что дальнейшую тренировку можно считать избыточной. Вы вот сюда посмотрите, прежде чем предположения о моей квалификации делать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Здравствуйте, gandjustas, Вы писали:
ГВ>>>А тебе ключи от сейфа не надо? Упрись, там и разберёшься, что на что влияет. Просто прими как факт, что есть такие предметные области, где 30 микросекунд latency — "слив зощитан", а 1,5 микросекунды — топ продаж. Но вообще, тебе о том знать не надобно, так оно проще: я ничего не имею против того, чтобы абсолютное большинство озабочивалось latency, когда оно превысит сотни миллисекунд.
G>>Не думаю что слово "коробочный" к такому ПО применимо.
ГВ>Что тут сказать? Нельзя спорить с негативно сформулированными тезисами, тем более, если они оформлены как личное мнение.
У тебя другое мнение? Озвучивай его? Или ты споришь для того чтобы спорить?
ГВ>Молодцы. Только это никак не отменяет того, что приведённая цитата содержит банальность.
Именно, но даже эту банальность не все знают и понимают.
ГВ>>>Замеры замерам рознь. Я тебя уверяю, цифры, которые выдаёт профайлер в синтетических тестах, далеко не всегда подходят для выводов о производительности в реальных условиях. G>>Отсутствие каких-либо цифр не лучше. Попытка делать хоть какие-то выводы в таком случае — шаманство.
ГВ>Никто не спорит с тем, что цифры полезны. Вопрос в том, как их получить и как потом применить. В случае серьёзных требований к производительности и то, и другое может оказаться весьма нетривиальными задачами.
"Серьезные требования к производительности" лежит за пределами коробочного ПО. А значит там можно говорить только о достаточно производительности.
Да и есть сомнения что в коробочном ПО имеет значение любая другая производительность кроме "достаточной".
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Здравствуйте, gandjustas, Вы писали:
ГВ>>>Молодцы. Только это никак не отменяет того, что приведённая цитата содержит банальность. G>>Именно, но даже эту банальность не все знают и понимают.
ГВ>А... Ну да, в общем. Извини, я не ожидал, что всё вокруг настолько плохо, что даже банальности не всем понятны, и эта непонятливость настолько велика, что ты её автоматически переносишь на любых оппонентов.
Не на любых, а только на тех кто говорят что важно априорное знание о характеристиках быстродействия кода. Причем на проверку это априорное знание даже на простом коде не помогло.
И дело даже не в том что люди умеют или не умеют оптимизировать, а в том что некоторые вместо инженерного подхода используют "шаманский", а потом сильно бравируют этим.
DG>>в первой строчке, ты говоришь что: челы не знали что делать, но ты им принес "тайные знания", и они сразу проблему решили. DG>>во второй сторочке, ты говоришь, что "тайных знаний" не бывает. G>То что надо мерить — не тайные знания. Тем не менее не всем они известны.
если они не тайные, то это означает, что ты сейчас можешь предоставить конкретный алгоритм, который для любого проекта конкретно скажет, что и как надо измерять.
когда же такого алгоритма нет (как в данном случае), то требуется гуру-шаман, который сможет общую рекомендацию (давайте что-нибудь померяем, и жизнь сразу наладится) перевести в конкретные точки измерения.
Здравствуйте, gandjustas, Вы писали:
V>>А где ты видел "отсутствие каких-либо цифр"? Речь шла зашла о сценариях применения профайлеров. В любом случае дотнетный профайлер не поможет, когда доходит до уровня игр с разной грануляцией блокировок, переделкой алгоритмов в многопоточные или обратно и т.д., борьбой с издержкой кешей, затрат на переключения контекстов и т.д. Тут уместны уже нейтивные от интел или амд для нейтивных же программ.
G>Не надо усложнять. Ты говорил что надо уметь "видеть" проблемы быстродействия в коде, тебе дали элементарный код, но ты в нем проблему не увидел.
Была указана проблема в линейном алгоритме, который предлагалось целиком заменить на другой, в терминах O(n). Я тебе это уже писал рядом, подзабыл?
ПЕРЕД началом оптимизаций, программу необходимо переписать. ... а вместо генерации всех вариантов ReplaceQuestionMarks написать алгоритм непосредственного сравнения паттернов с "??". Т.е. для начала сделать преобразования алгоритмов в терминах O(n). И только после доработки алгоритмов можно приступать шлифовать коэффициент K при O(n).
А ты сейчас встал в позицию Липперта, который там пошагово улучшает алгоритм, который всё-равно придется выкинуть целиком на очередной итерации. Это выглядит жалко.
G>Как ты собираешься в сложных случаях без измерений вообще что-то делать?
Коллега, результаты измерений еще уметь толковать надо, чтобы быть уверенным что ты замерил именно то и именно там. А для этого надо уметь оценивать вычислительную сложность алгоритмов.
G>Ты выдвигал тезис о том что априори важно понимать как работает тот или иной код с точки зрения быстродействия. Тебе уже не один человек говорит что это необязательное условие, что в первую очередь надо мерить.
Нет, я уже подробно свою мысль пояснял. В первую очередь — это подготовить адекватные тестовые сценарии, иначе результатами замеров можно будет подтереться. А чтобы подготовить адекватные тестовые сценарии для примера чуть сложнее чем по ссылке, таки придется разбирать код... А там как раз и увидишь те самые "узкие" места автоматически, если будешь этим заниматься регулярно. Об этом "побочном эффекте" я и говорил. Могу опять повторить, что совсем от профайлеров никто не отказывается, не идиоты же, просто бежать сломя голову с профайлером наперевес, как тут слишком часто стали рекомендовать — это вредный совет. Хотя, если for fun only — почему бы и нет...
Здравствуйте, Sinclair, Вы писали:
S>Я же ответил. У вас трудности с восприятием? S>Повторю: Ну, как бы по определению: S>
S>In computer science, imperative programming is a programming paradigm that describes computation in terms of statements that change a program state
Хм, а после того, как современные императивные языки ввели объявление переменной вместе с ее инициализацией, парадигма сильно пострадала?
Ну вот в терминах С где-то так:
SomeType1 var1;
SomeType2 var2;
var1 = calculate1();
var2 = calculate2(var1);
В C++ это уже так:
SomeType1 var1 = calculate1();
SomeType2 var2 = calculate2(var1);
Второй вариант уже перестал быть императивной последовательностью вычислений или еще нет?
Если на твой взгляд перестал, то я согласен убрать слово "императивный", оставить только "последовательность вычислений", бо тут слишком много филосовского в той области, которая мне неинтересна.
Ключевое, как говорил, это таки последовательность операций над исходными и промежуточными данными.
V>>Некоторые не совсем те, некоторые совсем те. S>Даже если бы были те, которые "совсем те", важно то, что есть "совсем не те".
Дык, со вторым-то никто не спорит. Но ты на основании второго утверждаешь первое.
V>>В каком месте ты это увидел? Давай пошагово, как ты пришел к такому выводу. S>Перечитайте текст, на который вы отвечаете, ещё раз. Есть три фразы: S>
S>С точки зрения математики комплексных чисел, операция умножения a * b не имеет никакой "стоимости".
S>А вот если мы перейдём к некоторому представлению комплексных чисел в компьютере, то операция a * b будет иметь некоторую реализацию в этом представлении.
S>И вот уже у этой реализации будет некоторая стоимость, выраженная в терминах более низкоуровневых операций.
Для принятия решений оптимизатором достаточно некоей формулы от неких характеристик данных (я же упоминал К*O(n), под этим всегда есть некая формула f(n1, n2, ...)), а стоимость в терминах низкоуровневых операциях практически не интересует. Интересует просто стоимость операции f при таких-то входных n. Т.к. оптимизатор оперирует относительными величинами, я называю эту стоимость "в попугаях".
S>Вы в ответ на мою первую возражаете моей же третьей, а потом внезапно обнаруживаете "противоречие". Рекомендую прекратить принимать то, что вы принимаете, что бы это ни было.
Там уже было поскипано столько контекстов, что в другой раз желательно восстановить его целиком, чтобы я мог раскрыть рассуждения, т.е. дабы не вызвать такой реакции непонимания. Если я что-то в твоих постах не понял — мне не лень переспросить, хотел бы видеть сей простой прием в ответ... тут же не диссертация, мы пишем максимально кратко, подразумевая многое как известное (и все-равно дохрена букв выходит)..
V>>Обоснуй в терминах реляционной модели, плиз. Давай, отноешния, аттрибуты, вывод незначимости аттрибута из-за наличия таких-то зависимостей. Давай уже заканчивать разводить пустые ля-ля, ближе к телу. S>А куда ближе? Возьмём ваш собственный пример (надеюсь, с его пониманием у вас проблем не будет?): S>
S>Простейший пример: есть некая схема R {ABCD}, и заданы зависимости A->B, B->CD. Для этой схемы будет уместна декомпозиция {AB, BCD}, причем, в реальной СУБД мы во втором отношении можем создать индекс B, сугубо эффективности ради, но! это будет означать лишь еще раз произвести декомпозицию по всем правилам декомпозиций с вводом специального аттрибута-ключа B#, для требований сохранения исходной зависимости B->CD транзитивно через B->B#, B#->CD. В итоге получим декомпозицию заданной схемы в виде: {AB, BB#, B#CD}.
S>Вот вы ввели отношение BB#. Зачем оно? Оно не привносит никакой новой информации. Потому что у нас B<->B#.
Угу, т.е. закончили сугубо риторическим вопросом? Так это было возражение или просьба объяснить? ХЗ, что ты хотел этим показать... Встречный вопрос: для чего вообще существуют нормальные формы (аж пять популярных штук)? Ведь с т.з. реляционой теории декомозированная схема отношения абсолютно эквивалентна исходной? Это собственно то, отчего уже тяжко обсуждать сей предмет, бо ответы написаны во всех учебниках: исключительно ради эффективности реализации хранилища, более незачем. Вот тебе переход от теории к реализации, от заданной изначально недекомпозированной схемы к конкретной декомпозированной. И устройство индексов не исключение. Я думаю, что вместо риторических вопросов стоило проявить немного воображения, представить себя разработчиком СУБД. Характер значений B# должен быть таким, чтобы получать "остаток" отношения CD по B# за O(1). Это не обязательно хеш-таблица, это может быть какой-нить числовой адрес, даже многомерный, все-равно будет O(1).
Кстати, просматривая гугл по теме наткнулся на статью относительно индексов:
Кластерный индекс использует row locator и он является частью не кластерного индекса на leaf level. Этот факт приводит к важному правилу SQL Server: создавайте кластерные ключи как можно более короткими. Каждый некластерный индекс будет использовать значения кластерного индекса. Следовательно увеличение размера кластерного индекса приводит к многократному увеличению требований по памяти для всех не кластерных индексов. Последнее приводит к увеличению времени на процессы чтения, сканирования данных и, как следствие, к снижению общей производительности системы. Еще одно наблюдение – увеличение длины ключа приводит к снижению количества записей индекса, способных уместиться в пределах одной страницы, как следствие – к увеличению операций чтения-записи.
Полностью совпадает с моими наблюдениями, и никак не коррелирует с "превосходством кластерного индекса" в твоем видении происходящего. Рекомендацию относительно того, как правильно готовить кластерные индексы, я дал.. ключевое только размер данных таблицы, в которой определен кластерный индекс. Насчет блобов (чтобы уже поставить точку), они именно затем и не хранятся вместе с остальными данными таблицы, чтобы обеспечить адекватную работу технологии кластерных индексов. Которые таки отлично подходят для относительно небольших объемов данных. В общем, вот что я имел ввиду, говоря, что блобы в MS SQL еще как при чем относительно этой темы про индексы.
V>>Ну это ход конем, конечно, в реализации программы "оставаться в рамках неё"... Ничего, что у меня целые числа ограниченной разрядности, для начала? S>Ну, вообще говоря, это надо учитывать. А вы не знали? Соотношения, справедливые для "абстрактной арифметики целых чисел" могут запросто потерять справедливость для "арифметики чисел по модулю 2^32". Если вам это не очевидно, то не стесняйтесь спрашивать.
Ну ок, надо было сразу перейти на простой и понятный обмен шпильками. Фигли нам...
Здесь я напомнил кое-что, хотя никто не потрудился обратить внимание, на что намекали... зато могу и впредь спрашивать? Как незамысловато протекает беседа... Ладно, давай завязывать, на что не лень здесь еще отвечу, бо ты уже потратил прилично времени, но потом не обещаю... Конкретно числа в компьютере были напоминанием обыденности ситуации неполного соответствия реализации и модели. Но это нам не мешает использовать матаппарат, до тех пор, пока мы будем находится в области ограничений реализации.
V>>По кластерному не всегда, зависит от размеров таблицы. При достаточно "широкой" таблице в несколько раз менее эффективен, чем некластерный. S>Теперь пошла в ход "ширина" таблицы. Вы мне лучше расскажите, при чём тут вмещаемость таблицы в оперативную память, которую вы упоминали в прошлый раз.
С самого начала упоминалась. Насчет памяти в силе, но объяснять облом. Лучше возьми какую-нить машинку с не очень большим объемом памяти, чтобы не заморачиваться со сверхобъемами, потсавь туда MS SQL и поэкспериментируй с кластерными индексами. Потом с некластерными. И все это с учетом того, что вынес некластерного индекса должен давать приличный профит в плане уменьшения физического объема сканируемых данных. Вот при чем тут "ширина" таблицы. Интересует ее ширина в байтах... Ну и помним, блобы в записях таблиц занимают 16 байт (по состоянию на MS SQL 2005), так что, относительную ширину можно организовать многим кол-вом полей. Как раз это характер таблиц справочных данных — 3-4 десятка полей, половина из них varchar(>80) — вполне себе подходящий вариант для некластерного индекса.
V>>От себя добавлю, что для подавляющего большинства обычных запросов, "без выкрутасов" конкретной СУБД, никакого расширения не требуется. S>А я от себя добавлю, что нет, для подавляющего большинства обычных запросов, "без выкрутасов", и без конкретной СУБД, таки требуется расширение.
Это как ты упоминал повторяющиеся записи в результатах? Мне даже трудно представить ход рассуждения, зачем это надо, т.е. почему в этом месте не идет какая-нить group by, чтобы привести результат к каноническому, годному для РА? Если у вас таких "подавляющее большинство", нахрена вам вообще MS SQL? Вместо файловой системы, что ле? По опыту организация магазинов, складов, бухгалтерий и т.д. — не помню ни разу, чтобы мне нужны были данные, не попадающие в ограничения реляционной модели.
V>>Таки над конкретной БД, чаще всего не предоставляя всех ср-в по оперированию ей, при этом. S>Да? А ISO SQL — он над какой конкретной БД?
Над никакой. Что, все СУБД реализуют стандарт SQL-92 целиком и не расширяют своими подробностями?
V>>При чем, далеко не во всех субд. Правила приведения этого домена к значению предиката указан в справочнике конкретной СУБД, но не в справочнике к стандарту SQL. S>Вы сами-то стандарт читали? http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt S>Курить раздел 8 до просветления. Подробнейшим образом изложены формальные правила исчисления предикатов в SQL. И таки да, предикат возвращает одно из трёх значений. Никакого приведения к двоичной логике нет — оно у вас в голове.
Читал, давно и многократно. Давай конкретную фразу/абзац/не_важно_что, которые должны что-то такое доказать. И причем тут моя голова, есть т.н. boolean test, для строки с where(predicate) если предикат is null должно приниматься какое-то решение, и решение это должно быть двоичное: включать эту строку в результат или нет. Другого не дано. (Справедливости ради есть тонкости для right/left join, да и то не на всех базах). Конкретно в твоем примере boolen test предиката, который null, означает false.
S>Вы бредите. Никакой ошибки не выдаётся (если, конечно, СУБД соответствует стандарту).
А какая СУБД целиком поддерживает стандарт? (уже спрашивал)
S>Выдаётся результат, который не соответствует результату в РА.
Почему? Если значение выражения по домену {true, false, null} приводимо к boolean (например через boolean test), то проблема явно надуманна. Тем более, что есть стандарт, где это прописано... В общем, мимо.
S>Я вам показал, какие проблемы возникают в реляционной модели.
Это у тебя в голове они возникают, а не в модели. Действительный пример был с повторяющимися записями в результате, но мне уже интересно, а смысл в них без агрегации? А с агрегацией — вот уже результат соответствует обсуждаемой теме.
S>Совершенно верно. И большая часть реальных баз данных "не подчиняется в дальнейшем реляционной теории".
Ты хотел сказать "большая часть реальных баз данных поддерживает возможность создания/оперирования данных, не подчиняющихся реляционной теории"? Ну пусть поддерживает, может кому-то и надо... Я за полтора десятка лет работы с SQL во всевозможнейших БД, начиная с самых экзотических еще с середины 90-х, эти возможности не использовал ни разу. Наверно, от недостатка образования.
S>Обсуждение выросло из способности программиста отличать особенности конкретной СУБД от ISO SQL, а его — от реляционной модели.
Повторюсь для невнимательных: стоит ровно противоположная задача: искать соответствия в аспектах своей частности к некоей известной модели, дабы не изобретать велосипеды. Поэтому искать отличия не надо, они получаются сами: это подмножество функциональности, которая выходит за рамки такого соответствия. А уж рассуждать о "способностях" для таких основополагающих примитивов деятельности программиста — ну это низкопробнейший обмен шпильками, что еще сказать... лучше бы опять послал почитать что-нить, иногда люди бывает подкидывают любопытные ссылки...
V>>Красиво ты поспешил с выводами... ведь это смотря какой результат будет формирован в конце, зачастую ровно наоборот: distinc "где-то в середине" способен поднять эффективность многократно. S>Я не поспешил, это вы спешите с интерпретацией. Мало ли что "зачастую". Вопрос в том — сколько будет случаев, где производительность просядет? Именно из-за них выбор, работать ли с множествами или с мультимножествами, отдан программисту. "Чистая" РМ оказалась нежизнеспособной на практике.
То, что тебе дали дополнительный инструмент, разве означает, что первоначальный не нужен? Просто у тебя теперь более одного инструмента (или один, но расширенный). И таки мне было бы интересно посмотреть на пример, где данные заведомо будут повторяющиеся в промежуточных результатах, когда исходные хотя бы в 3-й НФ, и distinct по этим промежуточным снизил бы производительность... Это надо голову поломать, такой пример придумать...
Гораздо легче его придумать для базы, не находящейся в НФ >=3. Но сценарии использовании СУБД вместо файловой системы я обсуждать все равно не буду, сорри.
V>>А реляционного исчисления? А всех наработок реляционной теории БД? S>Всех теоретических наработок — достаточно. Я просто настаиваю на том, чтобы отделять мух от котлет.
Ну вот отделил ты операцию "фактор" от остальной РА, например. Поделишься ощущениями? Я помню эту операцию в связке с операциями РА, просто достаточно отмечать её особенность, почему не включили в РА.
V>>Э, нет. Ты мне о том, что эти комплексные числа нужно изобрести каждый раз заново, а я тебе — так вот же, учебник по вышке. S>Где вы нашли у меня такое утверждение?
Это отрицание возможности применения наработок и опыта по РА для реализации некластерных индексов, например. Твоя позиция "здесь всё по-другому"... Да ради бога, но для очень многого таки можно не изобретать ни велосипедов, ни терминологию, ни изучать св-в операций и т.д., а брать готовое (ведь есть понятия эквивалентность операций и отношений, пока в рамках РА можно пользоваться готовым аппараттом, не разрабатывая "на коленке" свой). Мне такой подход кажется очень удобным для практической работы.
V>>Тогда для чего оно надо? (есть тут смайлик печальной улыбки?) S>Как основа для более реальных теорий. Релятивистская механика точнее ньютоновской, но это не означает, что ньютоновскую не нужно изучать.
Блин, сам же даешь неплохие аналогии, и сам же против них споришь... В 99% случаев ньютоновской за глаза в обычной жизни. А если по какой-то частности не хватает ньютоновской, то берут релятивистскую, но только по этой частности. Так же проще.
V>>Можно я избавлю себя от поиска соответствия "последовательного алгоритма" и "императивного программирования"? S>Нет, нельзя. Это же вы пытаетесь применять их как синонимы:
Я уже раз 10 уточнил с тех пор, и задал вопрос в начале, сравнив С и С++. Где там большая императивность? Или лишь бы "прищучить" пофиг на чем? По этой теме не выйдет.
S>Нет, это не позволяет такого утверждать. Поймите, в РА нет никаких "вычислений". Есть декларации того, как "выход" операции связан со "входом". РА не обязывает исполнителя реально "просматривать" кортежи при выполнении этих операций. РА не обязывает исполнителя формировать промежуточные результаты в сколь бы то ни было воспринимаемом виде. Понимаете?
А какое нам дело до промежуточных результатов? Разве я хоть раз настаивал хоть на одной подробности реализации? Тем паче, что их много.
S>Я имею право как угодно переупорядочивать операции, если семантика сохраняется.
Не можешь! Сколько еще об этом говорить? пока по ссылке не прорешаешь задачи, так и будешь гнуть свое, основываясь на слухах и общей эрудиции..
Если ты имеешь ввиду, что одну и ту же формулу реляционного исчисления можно решить несколькими способами, то это будут именно что разные способы. У тебя будет не просто разный порядок неких операций, но обязательно разные сами аргументы в операциях РА и в общем случае (кроме вырожденных) будут получаться разные типы промежуточных отношений. Да, коль SQL близок к исчислению кортежей, то для удовлетворения запроса может быть составлено много вариантов решений в терминах РА. Вот здесь уже ты путаешь РА и РИ.
S>И есть даже специальные соотношения эквивалентности, которые помогают мне это делать.
На уровне РА отношения эквивалентности есть только у тех операций, которые выразимы через другие... Т.е. реально базис мог бы быть составлен не из 7-ми, а из 5-ти операций, но ты ведь не это имел ввиду, надеюсь, а вообще любые операции? Так вот, эквивалентность только через РИ и работает. А когда расписали задачу в терминах РА, то уже можно идти писать программу, от самый физический уровень. Собственно, инструмент РА был придуман для того, чтобы обслуживать РИ, а ты утверждаешь, что он нужен сам по себе. Сам по себе РА крайне неудобен, т.к. навскидку сложно сказать, что будет являться результатом некоей последовательности операций, поэтому всегда РА используют как механизм для перехода из декларативного описания в терминах РИ к алгоритму в терминах РА.
А все рассуждения о "промежуточных результатах" — это в пользу бедных. Курсоры, итераторы и ленивость — чем не промежуточный результат? Это именно классика работы БД, бо они именно для такого сценария и были придуманы, т.е. для работы на очень ограниченном объеме оперативной памяти, в сравнении с объемом обрабатываемых данных. Сдается мне, что пытаясь рассуждать о промежуточных результатах, ты опять пытаешься мне что-то приписать. ИМХО, лучше напрямую спросить мое мнение, чем спорить с не моим в ответе мне.
Здравствуйте, gandjustas, Вы писали:
G>И дело даже не в том что люди умеют или не умеют оптимизировать, а в том что некоторые вместо инженерного подхода используют "шаманский", а потом сильно бравируют этим.
Нет никакого шаманства, ровно наоборот: сухое применение наработок, полученных в аналогичных условиях. В любом случае, все оптимизации идут под присмотром тестов на производительность (как минимум), я лишь сказал, что практически в 100% эти места видны и без профайлеров. Например, целиком алгоритм по ссылке. Читая по диагонали было видно, что генерируются всевозможные комбинации из букв, включая ?, затем полученное сравнивается со всем словарем. Как конкретно сравнивается — уже не важно, сам такой алгоритм уже не пойдет, о чем тут же и сказал.
Здравствуйте, vdimas, Вы писали:
V>Второй вариант уже перестал быть императивной последовательностью вычислений или еще нет?
Вариант — да. Язык — нет, т.к. он позволяет делать и другие "варианты".
V>Для принятия решений оптимизатором достаточно некоей формулы от неких характеристик данных (я же упоминал К*O(n), под этим всегда есть некая формула f(n1, n2, ...)), а стоимость в терминах низкоуровневых операциях практически не интересует.
Ок, хорошо.
V>Там уже было поскипано столько контекстов, что в другой раз желательно восстановить его целиком, чтобы я мог раскрыть рассуждения, т.е. дабы не вызвать такой реакции непонимания.
Вы просто читайте текст подряд и понимайте головой. V>Угу, т.е. закончили сугубо риторическим вопросом? Так это было возражение или просьба объяснить? ХЗ, что ты хотел этим показать... Встречный вопрос: для чего вообще существуют нормальные формы (аж пять популярных штук)? Ведь с т.з. реляционой теории декомозированная схема отношения абсолютно эквивалентна исходной? Это собственно то, отчего уже тяжко обсуждать сей предмет, бо ответы написаны во всех учебниках: исключительно ради эффективности реализации хранилища, более незачем.
V>Полностью совпадает с моими наблюдениями, и никак не коррелирует с "превосходством кластерного индекса" в твоем видении происходящего.
Ну как это "не коррелирует". Цитирую:
2. В случае наличия кластерного индекса, остальные индексы вместо RID используют ключ кластерного индекса. Поэтому не стоит делать кластерный индекс по длинному ключу, если других индексов много
V>Рекомендацию относительно того, как правильно готовить кластерные индексы, я дал.. ключевое только размер данных таблицы, в которой определен кластерный индекс.
Эта рекомендация — полный бред. Размер данных таблицы не играет никакой роли. Вы не понимаете разницы между размером ключа и размером таблицы, что бы вы этим "размером" ни называли? В прошлый раз вы упоминали, что таблица для кластерного индекса должна целиком влезать в ОП — это полный бред. Не должна. Сейчас, вроде бы, подразумеваете, что "размер таблицы" — это размер одного кортежа. Тоже мимо тазика — размер ключа кластерного индекса определяется независимо от размера индексируемых кортежей.
V>Насчет блобов (чтобы уже поставить точку), они именно затем и не хранятся вместе с остальными данными таблицы, чтобы обеспечить адекватную работу технологии кластерных индексов.
Вы по-прежнему бредите. Кластерным индексам всё равно, есть в таблице блобы, и где они хранятся. V>Которые таки отлично подходят для относительно небольших объемов данных. В общем, вот что я имел ввиду, говоря, что блобы в MS SQL еще как при чем относительно этой темы про индексы.
У вас какое-то радикально неправильное понимание устройства кластерных индексов. Может, вам на примере объяснить?
Вот вам таблица
create table Person)
id int identity primary key,
passportNumber char(10) not null constraint passportNumber unique,
firstName varchar(max) not null,
lastName varchar(max) not null,
birthdate datetime not null,
picture varbinary(max),
// ещё поля на 4 килобайта
)
Она, вроде бы, широкая. В ней даже блобы есть. Вы что, всерьёз полагаете, что что-то может помешать эффективному использованию кластерного индекса по колонке passportNumber? Нет, ничего.
V>Здесь я напомнил кое-что, хотя никто не потрудился обратить внимание, на что намекали... зато могу и впредь спрашивать? Как незамысловато протекает беседа... Ладно, давай завязывать, на что не лень здесь еще отвечу, бо ты уже потратил прилично времени, но потом не обещаю... Конкретно числа в компьютере были напоминанием обыденности ситуации неполного соответствия реализации и модели. Но это нам не мешает использовать матаппарат, до тех пор, пока мы будем находится в области ограничений реализации.
Ключевое выделено. У вас, к примеру, понимание области ограничений весьма размыто. Это видно по непониманию, скажем, отличия трёхзначной логики от двузначной, и от последствий этого.
V>С самого начала упоминалась. Насчет памяти в силе, но объяснять облом. Лучше возьми какую-нить машинку с не очень большим объемом памяти, чтобы не заморачиваться со сверхобъемами, потсавь туда MS SQL и поэкспериментируй с кластерными индексами. Потом с некластерными.
В ответ рекомендую открыть SQL Books Online и погрузиться в описание архитектуры кластерных индексов. Я кагбэ все эти вещи на пузе исползал крайне подробно — в том числе и базы больше размера ОП, и прочее.
V>И все это с учетом того, что вынес некластерного индекса должен давать приличный профит в плане уменьшения физического объема сканируемых данных.
Откуда возьмётся уменьшение физического объёма сканируемых данных? Вы вообще понимаете, как работают индексы?
Вот при чем тут "ширина" таблицы. Интересует ее ширина в байтах... Ну и помним, блобы в записях таблиц занимают 16 байт (по состоянию на MS SQL 2005), так что, относительную ширину можно организовать многим кол-вом полей. Как раз это характер таблиц справочных данных — 3-4 десятка полей, половина из них varchar(>80) — вполне себе подходящий вариант для некластерного индекса.
Да и для кластерного тоже — самое оно. Вы в качестве ключа для индекса что предполагаете выбирать?
V>Это как ты упоминал повторяющиеся записи в результатах? Мне даже трудно представить ход рассуждения, зачем это надо, т.е. почему в этом месте не идет какая-нить group by, чтобы привести результат к каноническому, годному для РА?
Потому что на практике каноничность не интересна. Откройте произвольное приложение, которое работает с базой данных, и поищите, сколько раз встречается select, а сколько раз distinct. Это даст вам примерное представление о доле "РА-совместимых" запросов в типичном SQL. V>Если у вас таких "подавляющее большинство", нахрена вам вообще MS SQL? Вместо файловой системы, что ле? По опыту организация магазинов, складов, бухгалтерий и т.д. — не помню ни разу, чтобы мне нужны были данные, не попадающие в ограничения реляционной модели.
Это у вас оттого, что вы никогда не задумывались о том, что конкретно подразумевается под "ограничениями реляционной модели".
V>Над никакой. Что, все СУБД реализуют стандарт SQL-92 целиком и не расширяют своими подробностями?
Наоборот. Об этом я и говорю — есть уровень "ISO SQL" (в котором, к слову, даже индексов нет), а есть — уровень "конкретной субд". V>>>При чем, далеко не во всех субд. Правила приведения этого домена к значению предиката указан в справочнике конкретной СУБД, но не в справочнике к стандарту SQL. S>>Вы сами-то стандарт читали? http://www.contrib.andrew.cmu.edu/~shadow/sql/sql1992.txt S>>Курить раздел 8 до просветления. Подробнейшим образом изложены формальные правила исчисления предикатов в SQL. И таки да, предикат возвращает одно из трёх значений. Никакого приведения к двоичной логике нет — оно у вас в голове.
V>Читал, давно и многократно. Давай конкретную фразу/абзац/не_важно_что, которые должны что-то такое доказать.
8.1 <predicate>
Function
Specify a condition that can be evaluated to give a truth value of
true, false, or unknown.
V>И причем тут моя голова, есть т.н. boolean test, для строки с where(predicate) если предикат is null должно приниматься какое-то решение, и решение это должно быть двоичное: включать эту строку в результат или нет. Другого не дано.
И опять мы посмотрим в стандарт:
7.6 <where clause>
Function
Specify a table derived by the application of a <search condition>
to the result of the preceding <from clause>.
Format
<where clause> ::= WHERE <search condition>
...
General Rules
1) The <search condition> is applied to each row of T. The result
of the <where clause> is a table of those rows of T for which
the result of the <search condition> is true.
и далее:
8.12 <search condition>
Function
Specify a condition that has the truth value true, false, or
unknown, depending on the result of applying boolean operators
to specified conditions.
V>(Справедливости ради есть тонкости для right/left join, да и то не на всех базах). Конкретно в твоем примере boolen test предиката, который null, означает false.
Нет. прочитайте стандарт. Если бы в этом случае "булевый тест" предиката означал false (а стандарт требует вовсе не этого), то NOT() от этого предиката означал бы true. Это называется "закон исключённого третьего", и он не работает в трёхзначной логике.
V>А какая СУБД целиком поддерживает стандарт? (уже спрашивал)
Зачем целиком? Достаточно поддерживать основные положения. Скажем, в трактовке NULL-ов у MS SQL даже есть опция SET ANSI_NULLS.
S>>Выдаётся результат, который не соответствует результату в РА. V>Почему? Если значение выражения по домену {true, false, null} приводимо к boolean (например через boolean test), то проблема явно надуманна. Тем более, что есть стандарт, где это прописано... В общем, мимо.
Что "почему"? Почему результат не соответствует результату в РА? Потому что в РА должно вернуться три кортежа, а в SQL — два. Найдите одно различие.
V>Это у тебя в голове они возникают, а не в модели. Действительный пример был с повторяющимися записями в результате, но мне уже интересно, а смысл в них без агрегации? А с агрегацией — вот уже результат соответствует обсуждаемой теме.
Я начинаю уставать ходить по кругу. Смысл — в повышении производительности. Если бы этого не было, то никто бы не стал заморачиваться поддержкой мультисетов, и в стандарт бы сразу запихали принудительную агрегацию всех промежуточных результатов.
V>Ты хотел сказать "большая часть реальных баз данных поддерживает возможность создания/оперирования данных, не подчиняющихся реляционной теории"? Ну пусть поддерживает, может кому-то и надо... Я за полтора десятка лет работы с SQL во всевозможнейших БД, начиная с самых экзотических еще с середины 90-х, эти возможности не использовал ни разу. Наверно, от недостатка образования.
Вы эти возможности использовали постоянно. Просто в силу особенностей мышления (с обсуждения которых и начался этот тред) вы так и не осознали, где вы выходили за границы реляционной модели.
V>Повторюсь для невнимательных: стоит ровно противоположная задача: искать соответствия в аспектах своей частности к некоей известной модели, дабы не изобретать велосипеды.
Чтобы искать соответствия, нужно сначала овладеть навыками анализа, т.е. разложения комплексных понятий на элементарные "запчасти".
Потом уже можно искать соответствия между этими "запчастями" и "запчастями" из других моделей, а также заниматься "синтезом" — сборкой комплексных понятий из полученных "запчастей".
V>Поэтому искать отличия не надо, они получаются сами: это подмножество функциональности, которая выходит за рамки такого соответствия.
Для начала нужно вообще иметь понятие о том, что есть рамки такого соответствия. Я уже почти неделю объясняю вам рамки соответствия реальных промышленных СУБД чистой реляционной модели — и несмотря на предположительное наличие у вас опыта и в теории, и на практике, дело идёт со скрипом. Даже когда я вам эти рамки сую под нос в детальных примерах и цитатах, они оказываются трудновоспринимаемыми. А вы говорите — "получаются сами".
V>А уж рассуждать о "способностях" для таких основополагающих примитивов деятельности программиста — ну это низкопробнейший обмен шпильками, что еще сказать... лучше бы опять послал почитать что-нить, иногда люди бывает подкидывают любопытные ссылки...
Да без проблем: http://wikipedia.org
Ещё рекомендую в гугле делать поиск с define: — это каждый раз, когда вам хочется придумать новый термин.
V>То, что тебе дали дополнительный инструмент, разве означает, что первоначальный не нужен?
Я не говорю, что он не нужен. Вы спорите сами с собой. Я говорю о том, что существует разница между реляционной моделью у Кодда, расширенной реляционной моделью, и моделью устройства реальной промышленной СУБД.
V>Просто у тебя теперь более одного инструмента (или один, но расширенный). И таки мне было бы интересно посмотреть на пример, где данные заведомо будут повторяющиеся в промежуточных результатах, когда исходные хотя бы в 3-й НФ, и distinct по этим промежуточным снизил бы производительность... Это надо голову поломать, такой пример придумать...
Да что тут ломать-то? Независимо от НФ, любая проекция, не включающая в себя primary key, сразу даст вам потенциальные повторы. Дистинкт по этим данным конечно же снизит производительность — потому что это group by со всеми вытекающими. В частности, нельзя использовать стриминг и резко возрастает потребность в буферах для промежуточных результатов. При низком коэффициенте повторяемости гораздо эффективнее отложить этот group by до момента, когда он реально нужен.
V>Ну вот отделил ты операцию "фактор" от остальной РА, например. Поделишься ощущениями?
Прекрасные ощущения, а что?
V>Это отрицание возможности применения наработок и опыта по РА для реализации некластерных индексов, например.
Какие именно наработки РА вы хотите применить для реализации некластерных индексов?
V>Блин, сам же даешь неплохие аналогии, и сам же против них споришь... В 99% случаев ньютоновской за глаза в обычной жизни. А если по какой-то частности не хватает ньютоновской, то берут релятивистскую, но только по этой частности. Так же проще.
Не "по какой-то частности", а "для какой-то задачи". И если в задаче нужна релятивистская механика, то будь любезен всю её решать в ней. А не так, что, скажем, скорости ты считаешь релятивистски, а время принимаешь ньютоновским.
V>Я уже раз 10 уточнил с тех пор, и задал вопрос в начале, сравнив С и С++.
Не вижу никакого уточнения. Или вы там в оффлайне уточняли? V>Где там большая императивность? Или лишь бы "прищучить" пофиг на чем? По этой теме не выйдет.
Да у вас куда ни ткни — везде непонимание и заблуждения.
V>А какое нам дело до промежуточных результатов? Разве я хоть раз настаивал хоть на одной подробности реализации? Тем паче, что их много.
Как какое? Вы же сами пишете, что результат операции зависит от результатов других операций. Это и есть промежуточные результаты, как бы по определению.
S>>Я имею право как угодно переупорядочивать операции, если семантика сохраняется. V>Не можешь!
ОМГ. Ну откуда, откуда это упорство в заблуждениях? http://en.wikipedia.org/wiki/Relational_algebra#Use_of_algebraic_properties_for_query_optimization
Прочтите весь раздел. Если в нём что-то непонятно, задайте дополнительные вопросы.
S>>И есть даже специальные соотношения эквивалентности, которые помогают мне это делать. V>На уровне РА отношения эквивалентности есть только у тех операций, которые выразимы через другие...
Повторюсь: http://en.wikipedia.org/wiki/Relational_algebra#Use_of_algebraic_properties_for_query_optimization
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>как только в выделенном найдешь (или в другом месте текста про identity), что change объекта не имеет права создавать новые копии
объекта, тогда продолжим разговор.
Это, простите, чушь. change объекта и создание нового объекта — разные вещи. Они не являются взаимоисключающими, но в вашем примере никакого change нету. Есть только создание новых объектов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Это, простите, чушь. change объекта и создание нового объекта — разные вещи. Они не являются взаимоисключающими, но в вашем примере никакого change нету. Есть только создание новых объектов.
ты постоянно скатываешься в область веры, и не можешь обосновать свои утверждения — это грустно...
Здравствуйте, DarkGray, Вы писали: DG>ты постоянно скатываешься в область веры, и не можешь обосновать свои утверждения — это грустно...
При чём тут вера? Вы всерьёз полагаете, что в поведение класса string в нужноверить?
Ну так я вас разочарую — нет, не нужно. Он уже ведёт себя вполне определённым образом.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>ты постоянно скатываешься в область веры, и не можешь обосновать свои утверждения — это грустно... S>При чём тут вера?
каждый твой довод основан на вере. ты говоришь "я верю, что это не ООП".
вообще, в познании мира выделяют три этапа:
1. шаманский
2. религиозный
3. научный.
на уровне шамана "правильно — не правильно" определяется на основе традиций, если так делали — значит правильно, если так не делали — значит не правильно.
на уровне последователя/жреца "правильно — не правильно" определяется на основе писания. Правильно то, что записано в Единство Правильной Книжке, или что говорил Единственно Правильный Авторитет; всё остальное — не правильно.
на уровне научного подхода "правильно — не правильно" определяется на основе формулирования остенсивных терминов и логического вывода следствий. правильно — если выводится, неправильно — если не выводится.
твое понимание программирования где-то между шаманским и религиозным: между "я так делал всегда и это есть правильно" и "так написано в Великом Писании ООП, поэтому это есть правильно".
Здравствуйте, DarkGray, Вы писали:
DG>>>ты постоянно скатываешься в область веры, и не можешь обосновать свои утверждения — это грустно... S>>При чём тут вера?
DG>каждый твой довод основан на вере. ты говоришь "я верю, что это не ООП".
DG>вообще, в познании мира выделяют три этапа: DG>1. шаманский DG>2. религиозный DG>3. научный.
DG>на уровне шамана "правильно — не правильно" определяется на основе традиций, если так делали — значит правильно, если так не делали — значит не правильно. DG>на уровне последователя/жреца "правильно — не правильно" определяется на основе писания. Правильно то, что записано в Единство Правильной Книжке, или что говорил Единственно Правильный Авторитет; всё остальное — не правильно. DG>на уровне научного подхода "правильно — не правильно" определяется на основе формулирования остенсивных терминов и логического вывода следствий. правильно — если выводится, неправильно — если не выводится.
Есть еще один этап, околонаучно-фантастический.
string y = "2";
Console.WriteLine(Object.ReferenceEquals(y, y));
Console.WriteLine(Object.ReferenceEquals(y + "1", y + "1"));
Происходит изменение объекта?
DG>твое понимание программирования где-то между шаманским и религиозным: между "я так делал всегда и это есть правильно" и "так написано в Великом Писании ООП, поэтому это есть правильно".
пока ты это не введешь как остенсивный термин, это все также будет взгляд шамана на действия профессора.
S>Можно увидеть логический вывод того, что в коде S>
S>string y = "2";
S>Console.WriteLine(Object.ReferenceEquals(y, y));
S>Console.WriteLine(Object.ReferenceEquals(y + "1", y + "1"));
S>
S>Происходит изменение объекта?
при следующих определениях:
состояние рассматривается только между строками
сигнатуры функции '+' рассматривается как: измененный_объект_x := объект_x + изменение, объект_х в следующий момент после '+' рассматривается как старая версия объекта_х
строка с одним и тем значением рассматривается как один и тот же объект
тогда между второй и третьей строкой происходит изменение объекта
на окончании третьей строки есть один объект со значением "21", две ссылки на него, и старая версия объекта со значением "2".
Здравствуйте, DarkGray, Вы писали:
DG>твое понимание программирования где-то между шаманским и религиозным: между "я так делал всегда и это есть правильно" и "так написано в Великом Писании ООП, поэтому это есть правильно".
Спасибо за подробный анализ устройства моего понимания программирования. К сожалению, он основан на заблуждениях.
Разубеждать вас я не собираюсь, т.к. не вижу смысла приводить какие-либо аргументы человеку, который то требует от меня доказать аксиому, то путает непрерывное отображение с непрерывным множеством.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>Есть еще один этап, околонаучно-фантастический.
DG>пока ты это не введешь как остенсивный термин, это все также будет взгляд шамана на действия профессора.
S>>Можно увидеть логический вывод того, что в коде S>>
S>>string y = "2";
S>>Console.WriteLine(Object.ReferenceEquals(y, y));
S>>Console.WriteLine(Object.ReferenceEquals(y + "1", y + "1"));
S>>
S>>Происходит изменение объекта?
DG>при следующих определениях:
Что общего у этих определений с ООП, кроме слова "объект"?
DG>состояние рассматривается только между строками
Внутри строки оно неопределено? Какое отношение между строками и состоянием?
DG>сигнатуры функции '+' рассматривается как: измененный_объект_x := объект_x + изменение, объект_х в следующий момент после '+' рассматривается как старая версия объекта_х
Что такое версия, и чем она отличается от объекта?
Согласно этому определению функции '+' над строками, порождение чего-то таки случилось, т.к. после этой операции есть "измененный объект" и "старая версия". Идентичность указывает именно на то, что "старая версия" не была порождена в процессе такого изменения и сохранила свою идентичность с момента до изменения. Ты можешь рассматривать операцию "+" как угодно, но это не отменит того, что она что-то породила, и что-то оставила неизменным. Можешь называть порожденную сущность измененным объектом, если это обеспечивает тебе интересное времяпровождение в терминологических спорах. Замечу только, что изменение в ООП сохраняет идентичность измененного объекта.
DG>строка с одним и тем значением рассматривается как один и тот же объект
И это тоже определение? Чем строка отличается от например StringBuilder-а, что для нее особенное определение вводится?
DG>тогда между второй и третьей строкой происходит изменение объекта DG>на окончании третьей строки есть один объект со значением "21", две ссылки на него, и старая версия объекта со значением "2".
Опираясь на вышеописанные определения, я бы предположил что изменений происходит 2. Сначала изменяется объект y, а потом изменяется старая версия y
Я не удовлетворен таким логическим выводом, т.к. он исходит из сомнительных определений, введенных ради самого вывода.
DG>>при следующих определениях: S>Что общего у этих определений с ООП, кроме слова "объект"?
то что при этом сохраняются все следствия, которые сделаны в ООП. или другими словами — система построенная на этих определениях эквивалента системе рассматриваемой в рамках ООП
DG>>состояние рассматривается только между строками S>Внутри строки оно неопределено? Какое отношение между строками и состоянием?
в данном случае, используется принцип инкапсуляции: строка рассматривается как черный ящик, и поведение строки фиксируется только на входе и выходе. с этой точки зрения, поведение внутри строки для наблюдателя неопределено.
DG>>сигнатуры функции '+' рассматривается как: измененный_объект_x := объект_x + изменение, объект_х в следующий момент после '+' рассматривается как старая версия объекта_х S>Что такое версия, и чем она отличается от объекта?
это состояние объекта в прошлом.
используется на чтение для получения информации, какое состояние объекта было в прошлом.
из всех версий объекта актуальной считается только последняя, и соответственно именно она образует реальный объект в настоящем, к которому применяются изменения.
S>Согласно этому определению функции '+' над строками, порождение чего-то таки случилось, т.к. после этой операции есть "измененный объект" и "старая версия". Идентичность указывает именно на то, что "старая версия" не была порождена в процессе такого изменения и сохранила свою идентичность с момента до изменения. Ты можешь рассматривать операцию "+" как угодно, но это не отменит того, что она что-то породила, и что-то оставила неизменным. Можешь называть порожденную сущность измененным объектом, если это обеспечивает тебе интересное времяпровождение в терминологических спорах. Замечу только, что изменение в ООП сохраняет идентичность измененного объекта.
софистика, или по русски словоблудие — из разряда "есть ли пуп у адама или нет?", данное занятия очень было распространено среди религиозных деятелей (и ты сейчас от них ни чем не отличаешься).
ты играешься словами, но при этом ты ни для одного слова не дал определения.
как только ты определишь понятия, все эти словеса рассыплятся в прах.
например, одна из формализаций термина "порождение": при рассмотрении двух моментов времени t и t1 порождением называется появление объекта в момент t1 с новым identity, которого не было в момент t.
при этом если функция "+" определена как указано выше, то появления нового identity нет, а значит и нет порождения.
DG>>строка с одним и тем значением рассматривается как один и тот же объект S>И это тоже определение? Чем строка отличается от например StringBuilder-а, что для нее особенное определение вводится?
DG>>тогда между второй и третьей строкой происходит изменение объекта DG>>на окончании третьей строки есть один объект со значением "21", две ссылки на него, и старая версия объекта со значением "2". S>Опираясь на вышеописанные определения, я бы предположил что изменений происходит 2. Сначала изменяется объект y, а потом изменяется старая версия y
так тоже можно рассматривать, но при этом будет необходимо по другому задать инкапсуляцию по времени.
вообще, я согласен с тобой, что этот пример сложный на выявление object identity (и в учебнике шел бы со звездочкой), поэтому я потом и привел более простой пример, в котором тоже самое увидеть намного проще.
S>Я не удовлетворен таким логическим выводом, т.к. он исходит из сомнительных определений, введенных ради самого вывода.
у тебя есть сомнение. отлично! это значит ты пытаешься думать. Формализуй свое сомнение, введя термины и логическими выводами показав противоречие — тогда ты реально начнешь думать.
DG>>>при следующих определениях: S>>Что общего у этих определений с ООП, кроме слова "объект"?
DG>то что при этом сохраняются все следствия, которые сделаны в ООП. или другими словами — система построенная на этих определениях эквивалента системе рассматриваемой в рамках ООП
С идентичностью тут явный бардак.
DG>>>состояние рассматривается только между строками S>>Внутри строки оно неопределено? Какое отношение между строками и состоянием?
DG>в данном случае, используется принцип инкапсуляции: строка рассматривается как черный ящик, и поведение строки фиксируется только на входе и выходе. с этой точки зрения, поведение внутри строки для наблюдателя неопределено.
Интересно, а для чего это не так?
DG>>>сигнатуры функции '+' рассматривается как: измененный_объект_x := объект_x + изменение, объект_х в следующий момент после '+' рассматривается как старая версия объекта_х S>>Что такое версия, и чем она отличается от объекта?
DG>это состояние объекта в прошлом. DG>используется на чтение для получения информации, какое состояние объекта было в прошлом. DG>из всех версий объекта актуальной считается только последняя, и соответственно именно она образует реальный объект в настоящем, к которому применяются изменения.
Как может быть определена актуальность версии? Что из этого актуальнее, y1 или y2?
string y1 = y + "1";
string y2 = y + "2";
S>>Согласно этому определению функции '+' над строками, порождение чего-то таки случилось, т.к. после этой операции есть "измененный объект" и "старая версия". Идентичность указывает именно на то, что "старая версия" не была порождена в процессе такого изменения и сохранила свою идентичность с момента до изменения. Ты можешь рассматривать операцию "+" как угодно, но это не отменит того, что она что-то породила, и что-то оставила неизменным. Можешь называть порожденную сущность измененным объектом, если это обеспечивает тебе интересное времяпровождение в терминологических спорах. Замечу только, что изменение в ООП сохраняет идентичность измененного объекта.
DG>софистика, или по русски словоблудие — из разряда "есть ли пуп у адама или нет?", данное занятия очень было распространено среди религиозных деятелей (и ты сейчас от них ни чем не отличаешься). DG>ты играешься словами, но при этом ты ни для одного слова не дал определения.
Я не даю определения тем вещам, которым они уже даны не мной.
DG>как только ты определишь понятия, все эти словеса рассыплятся в прах. DG>например, одна из формализаций термина "порождение": при рассмотрении двух моментов времени t и t1 порождением называется появление объекта в момент t1 с новым identity, которого не было в момент t. DG>при этом если функция "+" определена как указано выше, то появления нового identity нет, а значит и нет порождения.
Т.е. ты утверждаешь что у объектов y и (y + "1") same identity? Как ты отличишьь этот объект от (y + "2"), не зная, какая операция была выполнена вперед?
Если у тебя объект и версия имеют одну идентичность, то почему они различаются по значениям в один и тот же момент времени? Это противоречит определению идентичности.
DG>>>строка с одним и тем значением рассматривается как один и тот же объект S>>И это тоже определение? Чем строка отличается от например StringBuilder-а, что для нее особенное определение вводится?
Ты не объяснил обособленность строки в твоей системе определений
DG>>>тогда между второй и третьей строкой происходит изменение объекта DG>>>на окончании третьей строки есть один объект со значением "21", две ссылки на него, и старая версия объекта со значением "2". S>>Опираясь на вышеописанные определения, я бы предположил что изменений происходит 2. Сначала изменяется объект y, а потом изменяется старая версия y
DG>так тоже можно рассматривать, но при этом будет необходимо по другому задать инкапсуляцию по времени. DG>вообще, я согласен с тобой, что этот пример сложный на выявление object identity (и в учебнике шел бы со звездочкой), поэтому я потом и привел более простой пример, в котором тоже самое увидеть намного проще.
В простом примере нельзя увидеть то, о чем ты говоришь. Он демонстрирует обратное.
S>>Я не удовлетворен таким логическим выводом, т.к. он исходит из сомнительных определений, введенных ради самого вывода.
DG>у тебя есть сомнение. отлично! это значит ты пытаешься думать. Формализуй свое сомнение, введя термины и логическими выводами показав противоречие — тогда ты реально начнешь думать.
У меня нет сомнений. Я вижу что твои определения и примеры несовместимы с традиционным ООП.
DG>>в данном случае, используется принцип инкапсуляции: строка рассматривается как черный ящик, и поведение строки фиксируется только на входе и выходе. с этой точки зрения, поведение внутри строки для наблюдателя неопределено. S>Интересно, а для чего это не так?
например, с точки зрения конкретного компилятора поведение внутри строки строго определенно, что куда и как преобразуется.
S>Как может быть определена актуальность версии? Что из этого актуальнее, y1 или y2? S>
S>string y1 = y + "1";
S>string y2 = y + "2";
S>
на основе лишь этого куска все следующие рассмотрения будут верными:
y, y1, y2 — три разных объекта
y, y1 — один объект, y2 — другой объект
y, y2 — один объект, y1 — другой объект
y, y1, y2 — один и тот же объект, y1 и y2 — две разные ссылки на один и тот же объект
S>Я не даю определения тем вещам, которым они уже даны не мной.
в мире для одного и того же слова, есть сотни, а то и тысячи определений с разным уровнем точности, соответственно как минимум ты обязан зафиксировать какое именно определение используешь и на каком уровне точности.
DG>>как только ты определишь понятия, все эти словеса рассыплятся в прах. DG>>например, одна из формализаций термина "порождение": при рассмотрении двух моментов времени t и t1 порождением называется появление объекта в момент t1 с новым identity, которого не было в момент t. DG>>при этом если функция "+" определена как указано выше, то появления нового identity нет, а значит и нет порождения. S>Т.е. ты утверждаешь что у объектов y и (y + "1") same identity? Как ты отличишьь этот объект от (y + "2"), не зная, какая операция была выполнена вперед? S>Если у тебя объект и версия имеют одну идентичность, то почему они различаются по значениям в один и тот же момент времени? Это противоречит определению идентичности.
опять же как только выписываются все определения, то выясняется что никакого противоречия нет.
здесь есть две плоскости (две модели) — версионная и не версионная.
с точки зрения модели, которая не знает что такое версионность — функция идентичности считает объект одним и тем же, если совпадает идентичность объекта(из модели версионной) и версия объекта(из модели версионной), при этом эта модель считает две версии объекта совершенно разными объектами, которые никак между собой не связаны, что неудобно при рассмотрении многих сценариев.
> Если у тебя объект и версия имеют одну идентичность, то почему они различаются по значениям в один и тот же момент времени?
соответственно, с точки зрения неверсионной модели никакого противоречия нет, потому что объекты разные.
с точки зрения версионной модели противоречия тоже нет, потому что версионная модель допускает иметь одному и тому же объекту разные состояния для случая, когда это есть предыдущие состояния этого же объекта.
DG>>>>строка с одним и тем значением рассматривается как один и тот же объект S>>>И это тоже определение? Чем строка отличается от например StringBuilder-а, что для нее особенное определение вводится? S>Ты не объяснил обособленность строки в твоей системе определений
потому что string использует immutable-версионность (а не backup-версионность), в отличии от stringbuilder-а
S>У меня нет сомнений. Я вижу что твои определения и примеры несовместимы с традиционным ООП.
опять религиозный догматический вывод. для полного образа тебе еще не хватает криков "сжечь еретика на костре!.
S>Можно продолжить, что всевозможные строки это один объект, т.к. могут быть получены из пустой строки путем добавления значения, равного заданной строке.
область значений объекта в рамках object identity имеет низкую значимость. соответственно, из такого предположения никаких интересных выводов сделать невозможно.
с точки зрения object identity важна, в первую очередь, трасса объекта: на что и как влияет объект в какой момент времени.
S>>>Я не даю определения тем вещам, которым они уже даны не мной.
DG>>в мире для одного и того же слова, есть сотни, а то и тысячи определений с разным уровнем точности, соответственно как минимум ты обязан зафиксировать какое именно определение используешь и на каком уровне точности. S>Тут разве не было ссылки на определение ООП идентичности ?
определения в виде остенсивного термина точно не было.
в лучшем случае было: что для такой-то системы в качестве object identity можно взять вот такую штуку.
DG>>опять же как только выписываются все определения, то выясняется что никакого противоречия нет. S>Никакого противоречия тому что всевозможные строки идентичны?
где вся логическая цепочка: определения, выводы, противоречие?
в данной фразе я вижу только следующую цепочку: допустим что все строки идентичны, а такого не может потому что не может быть никогда: получили противоречие.
но во-первых само по себе доказательство какое-то странное, а во вторых даже если допустить что доказательство верное, то получается что не надо лишь делать допущение, что все строки идентичны.
DG>>здесь есть две плоскости (две модели) — версионная и не версионная. DG>>с точки зрения модели, которая не знает что такое версионность — функция идентичности считает объект одним и тем же, если совпадает идентичность объекта(из модели версионной) и версия объекта(из модели версионной), при этом эта модель считает две версии объекта совершенно разными объектами, которые никак между собой не связаны, что неудобно при рассмотрении многих сценариев. S>Ты уже приводил определение идентичности версионной модели?
для начала стоит зафиксировать, что такое object identity в ООП вообще:
object identity — это аксиоматическое(неопределяемое) понятие, которое можно описать как, эта штука, которая определяет что объект является сам собой. отмечу, что в науке термин неопределяемое понятие, это такое понятие, которое не может быть выражено через более простые(базовые) понятия.
в рамках дискуссии object identity удобно ввести через другое неопределяемое понятие "ссылка" (штука, через которую мы общаемся с объектом): object identity — есть функция, которая для двух ссылок возвращает true, если объект является тем же самым.
для версионной модели — такая функция в дополнении к true, возвращает еще какая перед нами версия, и является ли она актуальной.
S>А ты можешь ответить на вопрос, является ли объект предыдущим состоянием некого объекта, или это самостоятельный объект?
конечно, в рамках конкретной задачи, когда зафиксировано что из чего хотели получить.
S>Это значит что никогда не ясно, является ли string объектом, или неактуальной версией какого-то объекта?
ты это так говоришь, как будто это нарушает какой-то фундаментальный закон.
тут можно провести полную аналогию со светом, про который тоже никогда не ясно — частица он или волна.
всё относительно.
S>>>У меня нет сомнений. Я вижу что твои определения и примеры несовместимы с традиционным ООП.
DG>>опять религиозный догматический вывод. для полного образа тебе еще не хватает криков "сжечь еретика на костре!. S>Почему догматический? Идентичность строк с одним значением + сохранение идентичности при операции "+" влечет идентичность всевозможных строк вне зависимости от их происхождения по твоим определениям.
нет, же конечно. область значений имеет очень отдаленное отношение к идентичности.
если так же рассуждать, то выяснится, что в .net-е все объекты одинаковы, потому что адрес объекта из-за gc может принимать все значения за время жизни объекта.
S> Идентичность строк с одним значением + сохранение идентичности при операции "+" влечет идентичность всевозможных строк
переход не верен.
первая часть утверждения говорит про идентичность экземпляра объекта: операция '+' сохраняет идентичность переданного ей экземпляра объекта, вторая же часть — говорит про область значений.
и вот эту монолитность можно увидеть, только если аккуратно формулировать определения и аккуратно делать выкладки.
Здравствуйте, DarkGray, Вы писали:
S>>Можно продолжить, что всевозможные строки это один объект, т.к. могут быть получены из пустой строки путем добавления значения, равного заданной строке.
DG>область значений объекта в рамках object identity имеет низкую значимость. соответственно, из такого предположения никаких интересных выводов сделать невозможно.
Можно сделать вывод о том что ты не можешь отличать строковые объекты, т.к. они все идентичны. DG>с точки зрения object identity важна, в первую очередь, трасса объекта: на что и как влияет объект в какой момент времени.
С точки зрения identity важно уметь отличать объекты. Если ты их не можешь отличать, то трасса не нужна.
S>>Тут разве не было ссылки на определение ООП идентичности ?
DG>определения в виде остенсивного термина точно не было. DG>в лучшем случае было: что для такой-то системы в качестве object identity можно взять вот такую штуку.
Устроит? http://en.wikipedia.org/wiki/Identity_%28object-oriented_programming%29
An identity in object-oriented programming, object-oriented design and object-oriented analysis describes the property of objects that distinguishes them from other objects.
DG>>>опять же как только выписываются все определения, то выясняется что никакого противоречия нет. S>>Никакого противоречия тому что всевозможные строки идентичны?
DG>где вся логическая цепочка: определения, выводы, противоречие?
определения использованы твои. В частности об идентичности двух строк с одинаковым значением и сохранением идентичности операции сложения. Вывод я выделил выше (о том что всевозможные строки есть один объект). Противоречит определению ООП идентичности.
DG>в данной фразе я вижу только следующую цепочку: допустим что все строки идентичны, а такого не может потому что не может быть никогда: получили противоречие.
Это не допустим, что они идентичны. Это вывод из твоих определений. DG>но во-первых само по себе доказательство какое-то странное, а во вторых даже если допустить что доказательство верное, то получается что не надо лишь делать допущение, что все строки идентичны.
это не допущение, а следствие из твоих определений.
Если хочешь — сделай утверждение что в рамках твоих определений две строки с различным содержанием — разные объекты, и я докажу тебе с учетом транзитивности идентичности по твоим определениям это не так.
S>>Ты уже приводил определение идентичности версионной модели?
DG>для начала стоит зафиксировать, что такое object identity в ООП вообще: DG>object identity — это аксиоматическое(неопределяемое) понятие, которое можно описать как, эта штука, которая определяет что объект является сам собой. отмечу, что в науке термин неопределяемое понятие, это такое понятие, которое не может быть выражено через более простые(базовые) понятия. DG>в рамках дискуссии object identity удобно ввести через другое неопределяемое понятие "ссылка" (штука, через которую мы общаемся с объектом): object identity — есть функция, которая для двух ссылок возвращает true, если объект является тем же самым. DG>для версионной модели — такая функция в дополнении к true, возвращает еще какая перед нами версия, и является ли она актуальной.
Туманное дополнение. И что же такое актуальность версии? Когда версии становятся неактуальными? Твоя идентичность динамическая? Т.е. со временем она может меняться? Если да, то это противоречит определению ООП идентичности, в частности тому, что идентичность объекта сохраняется все его время жизни.
S>>А ты можешь ответить на вопрос, является ли объект предыдущим состоянием некого объекта, или это самостоятельный объект? DG>конечно, в рамках конкретной задачи, когда зафиксировано что из чего хотели получить.
если эта конкретная задача является частью другой задачи, то твой ответ не будет справедлив для другой задачи. Не смущает?
S>>Это значит что никогда не ясно, является ли string объектом, или неактуальной версией какого-то объекта?
DG>ты это так говоришь, как будто это нарушает какой-то фундаментальный закон. DG>тут можно провести полную аналогию со светом, про который тоже никогда не ясно — частица он или волна. DG>всё относительно.
Понятно. Т.е. когда тебе удобно, она объект, когда нет — версия. И всегда можно доказать что она и то и другое.
S>>>>У меня нет сомнений. Я вижу что твои определения и примеры несовместимы с традиционным ООП.
DG>>>опять религиозный догматический вывод. для полного образа тебе еще не хватает криков "сжечь еретика на костре!. S>>Почему догматический? Идентичность строк с одним значением + сохранение идентичности при операции "+" влечет идентичность всевозможных строк вне зависимости от их происхождения по твоим определениям.
DG>нет, же конечно. область значений имеет очень отдаленное отношение к идентичности. DG>если так же рассуждать, то выяснится, что в .net-е все объекты одинаковы, потому что адрес объекта из-за gc может принимать все значения за время жизни объекта.
За время жизни объекта — да, но не одновременно. Точно так же мутабельная строка за время жизни может принимать любые значения. И она ничего не нарушает в ООП идентичности.
S>> Идентичность строк с одним значением + сохранение идентичности при операции "+" влечет идентичность всевозможных строк
DG>переход не верен. DG>первая часть утверждения говорит про идентичность экземпляра объекта: операция '+' сохраняет идентичность переданного ей экземпляра объекта, вторая же часть — говорит про область значений.
Про область значений говорит другое твое определение, согласно которому все строки с одинаковым значением считаются одним объектом. DG>и вот эту монолитность можно увидеть, только если аккуратно формулировать определения и аккуратно делать выкладки.
Аккуратно как ты?
DG>>область значений объекта в рамках object identity имеет низкую значимость. соответственно, из такого предположения никаких интересных выводов сделать невозможно. S>Можно сделать вывод о том что ты не можешь отличать строковые объекты, т.к. они все идентичны.
нельзя сделать такой вывод.
я умею отличать трассы, а этого достаточно для идентификации объекта.
DG>>с точки зрения object identity важна, в первую очередь, трасса объекта: на что и как влияет объект в какой момент времени. S>С точки зрения identity важно уметь отличать объекты. Если ты их не можешь отличать, то трасса не нужна.
я утверждаю, что если трасса разная, то это разные объекты. ты же говоришь, что трасса не нужна, потому что это не дает отличия.
что значит "трасса не нужна", если как раз она и определяет одинаковость объектов?
S>An identity in object-oriented programming, object-oriented design and object-oriented analysis describes the property of objects that distinguishes them from other objects.
утверждение "давай отличать объекты по их трассам" подходит под данное определение, и никакого противоречия не возникает.
с чем ты тогда не согласен?
DG>>>>опять же как только выписываются все определения, то выясняется что никакого противоречия нет. S>>>Никакого противоречия тому что всевозможные строки идентичны?
DG>>где вся логическая цепочка: определения, выводы, противоречие? S>определения использованы твои. В частности об идентичности двух строк с одинаковым значением и сохранением идентичности операции сложения. Вывод я выделил выше (о том что всевозможные строки есть один объект). Противоречит определению ООП идентичности.
во-первых: какому слову из твоего определения это противоречит, и в чем?
во-вторых, еще раз повторю, что операция "+" сохраняет идентичность не произвольного объекта, а только того, который ей передали в данной конкретной программе.
DG>>в данной фразе я вижу только следующую цепочку: допустим что все строки идентичны, а такого не может потому что не может быть никогда: получили противоречие. S>Это не допустим, что они идентичны. Это вывод из твоих определений. DG>>но во-первых само по себе доказательство какое-то странное, а во вторых даже если допустить что доказательство верное, то получается что не надо лишь делать допущение, что все строки идентичны. S>это не допущение, а следствие из твоих определений. S>Если хочешь — сделай утверждение что в рамках твоих определений две строки с различным содержанием — разные объекты, и я докажу тебе с учетом транзитивности идентичности по твоим определениям это не так.
разные трассы — разные объекты.
S>Туманное дополнение. И что же такое актуальность версии? Когда версии становятся неактуальными? Твоя идентичность динамическая? Т.е. со временем она может меняться? Если да, то это противоречит определению ООП идентичности, в частности тому, что идентичность объекта сохраняется все его время жизни.
ты это сейчас сам придумал, в определении которое ты привел такого требования нет.
S>>>А ты можешь ответить на вопрос, является ли объект предыдущим состоянием некого объекта, или это самостоятельный объект? DG>>конечно, в рамках конкретной задачи, когда зафиксировано что из чего хотели получить. S>если эта конкретная задача является частью другой задачи, то твой ответ не будет справедлив для другой задачи. Не смущает?
нет, конечно. потому что этого требования (что различие объектов должно сохраняться для разных задач) в твоем определении тоже нет.
S>>>Это значит что никогда не ясно, является ли string объектом, или неактуальной версией какого-то объекта?
DG>>ты это так говоришь, как будто это нарушает какой-то фундаментальный закон. DG>>тут можно провести полную аналогию со светом, про который тоже никогда не ясно — частица он или волна. DG>>всё относительно. S>Понятно. Т.е. когда тебе удобно, она объект, когда нет — версия. И всегда можно доказать что она и то и другое.
конечно, в этом и смысл моделей. что они используются когда они удобны, и не используются когда не удобны.
например, отрезок можно рассматривать как две точки, как точку + вектор, как другую точку и обратный вектор, как центр + "радиус-вектор" и т.д. все эти рассмотрения одинаково верны, и в каждый момент времени будет использоваться то рассмотрение, которое более удобно именно в этот момент.
S>Про область значений говорит другое твое определение, согласно которому все строки с одинаковым значением считаются одним объектом.
только в конкретный момент времени, и при условии, что одинаковость сохраняется для всех вариантов входных данных
Здравствуйте, DarkGray, Вы писали:
DG>утверждение "давай отличать объекты по их трассам" подходит под данное определение, и никакого противоречия не возникает.
Не подходит. identity не должно зависеть от состояния и поведения и должно работать для любой пары объектов, даже тех типов, которые ты определишь после определения identity.
Попробуй такую функцию построить.
DG>>утверждение "давай отличать объекты по их трассам" подходит под данное определение, и никакого противоречия не возникает.
G>Не подходит. identity не должно зависеть от состояния и поведения и должно работать для любой пары объектов, даже тех типов, которые ты определишь после определения identity.
что здесь ООП-объект? и что здесь object identity?
так же стоит попробовать ответить на вопросы:
1. сколько объектов будет выведено?
2. сколько раз будет выведен каждый объект?
если на первые вопросы ответы:
в качестве ООП-объекта берется .net-объект
в качестве object identity берется ECMA-identity
то получается, что на последующие вопросы невозможно дать определенные ответы, и можно дать лишь ответы с высокой долей неопределенности:
1. будет выведено объектов от 1 до items.Count (или 0, если items.Count == 0)
2. каждый объект из списка может быть выведен от 1 до items.Count раз (утверждение имеет смысл только для items.Count > 0)
если же на первые вопросы ответы:
каждая ссылка из items есть ООП-объект
в качестве object identity берется условная ссылка items[x], где x — это последовательный номер от 0 до items.Count. при этом объекты, взятые по ссылкам items[x1] и items[x2] считаются разными объектами, если x1 != x2
такие ответы уже помогают получить определенные ответы на последующие вопросы:
1. будет выведено items.Count объектов
2. каждый объект будет выведен 1 раз (утверждение имеет смысл только для items.Count > 0)
при втором подходе даже для очень больших программ можно делать сложные утверждения с высокой долей определенности(что полезно при анализе корректности программы, оптимизации, трансляции и т.д.),
первый подход не дает ничего полезного даже на маленьких программах (и соответственно тогда не понятно — а на хрена его исповедовать?)
DG>>>область значений объекта в рамках object identity имеет низкую значимость. соответственно, из такого предположения никаких интересных выводов сделать невозможно. S>>Можно сделать вывод о том что ты не можешь отличать строковые объекты, т.к. они все идентичны.
DG>нельзя сделать такой вывод.
Я сделал такой вывод. Если хочешь — опровергни его. DG>я умею отличать трассы, а этого достаточно для идентификации объекта.
Этого не достаточно для идентификации объектов внутри трассы. Кроме этого, дополнение идентичности равнозначных строк ломает тебе идентификацию трасс объектов.
S>>С точки зрения identity важно уметь отличать объекты. Если ты их не можешь отличать, то трасса не нужна.
DG>я утверждаю, что если трасса разная, то это разные объекты. ты же говоришь, что трасса не нужна, потому что это не дает отличия. DG>что значит "трасса не нужна", если как раз она и определяет одинаковость объектов?
В том числе и она. Смотри свои определения.
S>>Устроит?
DG>в первом приближении — да. тем более что из этого определения следует, что функцию идентичности можно брать какую угодно, и тогда не понятно откуда у тебя берутся сомнения.
Какая угодно функция не может отличать объекты. Смотри свои трассы, например.
S>>http://en.wikipedia.org/wiki/Identity_%28object-oriented_programming%29 S>>
S>>An identity in object-oriented programming, object-oriented design and object-oriented analysis describes the property of objects that distinguishes them from other objects.
DG>утверждение "давай отличать объекты по их трассам" подходит под данное определение, и никакого противоречия не возникает. DG>с чем ты тогда не согласен?
Возникает. Ты не можешь отличить две строки. Программа не знает что такое трасса, нет способа определения принадлежности объектов одной трассе.
DG>>>где вся логическая цепочка: определения, выводы, противоречие? S>>определения использованы твои. В частности об идентичности двух строк с одинаковым значением и сохранением идентичности операции сложения. Вывод я выделил выше (о том что всевозможные строки есть один объект). Противоречит определению ООП идентичности.
DG>во-первых: какому слову из твоего определения это противоречит, и в чем?
Слову "отличать" и противоречит. В том, что ты не можешь отличить две строки.
DG>во-вторых, еще раз повторю, что операция "+" сохраняет идентичность не произвольного объекта, а только того, который ей передали в данной конкретной программе.
Интересное замечание. Ты определил идентичность только для "тех" объектов, которые переданы в операцию "+". А как ты их отличаешь до того как передаешь их в "+"? Ты ведь уже до передачи делишь объекты на "те" и не те".
Но это и не важно.
string s1 = "" + "1";
string s2 = "" + "2";
по твоим определениям "", s1 и s2 один и тот же объект.
DG>>>но во-первых само по себе доказательство какое-то странное, а во вторых даже если допустить что доказательство верное, то получается что не надо лишь делать допущение, что все строки идентичны. S>>это не допущение, а следствие из твоих определений. S>>Если хочешь — сделай утверждение что в рамках твоих определений две строки с различным содержанием — разные объекты, и я докажу тебе с учетом транзитивности идентичности по твоим определениям это не так.
DG>разные трассы — разные объекты.
Смотри свое определение о том что строки с равным значением это один и тот же объект.
S>>Туманное дополнение. И что же такое актуальность версии? Когда версии становятся неактуальными? Твоя идентичность динамическая? Т.е. со временем она может меняться? Если да, то это противоречит определению ООП идентичности, в частности тому, что идентичность объекта сохраняется все его время жизни.
DG>ты это сейчас сам придумал, в определении которое ты привел такого требования нет.
Вообще это не я придумал.
А в твоем определении нет понятия "версия"
S>>если эта конкретная задача является частью другой задачи, то твой ответ не будет справедлив для другой задачи. Не смущает?
DG>нет, конечно. потому что этого требования (что различие объектов должно сохраняться для разных задач) в твоем определении тоже нет.
Подскажи, какой смысл в идентичности без ее сохранения объектом? Вот определил ты что объекты разные, и в той же строчке не можешь гарантировать что они останутся разными. Foo("1", "2"). На входе разные объекты, внутри — один объект, на выходе один объект. Что дает такая идентичность?
DG>>>ты это так говоришь, как будто это нарушает какой-то фундаментальный закон. DG>>>тут можно провести полную аналогию со светом, про который тоже никогда не ясно — частица он или волна. DG>>>всё относительно. S>>Понятно. Т.е. когда тебе удобно, она объект, когда нет — версия. И всегда можно доказать что она и то и другое.
DG>конечно, в этом и смысл моделей. что они используются когда они удобны, и не используются когда не удобны.
Я не вижу в чем удобство твоей модели и нафига ее использовать.
DG>например, отрезок можно рассматривать как две точки, как точку + вектор, как другую точку и обратный вектор, как центр + "радиус-вектор" и т.д. все эти рассмотрения одинаково верны, и в каждый момент времени будет использоваться то рассмотрение, которое более удобно именно в этот момент.
Отрезок рассматривается как интервал. И это единственно верное его рассмотрение. Очевидно что интервал и две точки обладают различными свойствами, и не могут быть одинакого верны.
S>>Про область значений говорит другое твое определение, согласно которому все строки с одинаковым значением считаются одним объектом.
DG>только в конкретный момент времени, и при условии, что одинаковость сохраняется для всех вариантов входных данных
Я не понял смысла этой оговорки. И откуда она взялась? В твоих определениях ничего не было о времени и вариантов входных данных.
Здравствуйте, DarkGray, Вы писали:
DG>понятие объекта относительно (зависит от контекста), и также относительно понятие object identity.
DG>это отчасти видно на следующем примере DG>
DG>что здесь ООП-объект? и что здесь object identity?
DG>так же стоит попробовать ответить на вопросы: DG>1. сколько объектов будет выведено? DG>2. сколько раз будет выведен каждый объект?
DG>если на первые вопросы ответы: DG>в качестве ООП-объекта берется .net-объект DG>в качестве object identity берется ECMA-identity
DG>то получается, что на последующие вопросы невозможно дать определенные ответы, и можно дать лишь ответы с высокой долей неопределенности:
Можно дать ответы очень определенные. И сколько объектов, и сколько раз каждый. DG>1. будет выведено объектов от 1 до items.Count (или 0, если items.Count == 0)
Не факт. Может быть выведено 0 объектов при items.Count > 0. DG>2. каждый объект из списка может быть выведен от 1 до items.Count раз (утверждение имеет смысл только для items.Count > 0)
DG>если же на первые вопросы ответы: DG>каждая ссылка из items есть ООП-объект DG>в качестве object identity берется условная ссылка items[x], где x — это последовательный номер от 0 до items.Count. при этом объекты, взятые по ссылкам items[x1] и items[x2] считаются разными объектами, если x1 != x2
DG>такие ответы уже помогают получить определенные ответы на последующие вопросы: DG>1. будет выведено items.Count объектов DG>2. каждый объект будет выведен 1 раз (утверждение имеет смысл только для items.Count > 0)
DG>при втором подходе даже для очень больших программ можно делать сложные утверждения с высокой долей определенности(что полезно при анализе корректности программы, оптимизации, трансляции и т.д.), DG>первый подход не дает ничего полезного даже на маленьких программах (и соответственно тогда не понятно — а на хрена его исповедовать?)
Извини, но ты редкий извращенец. Сначала задаешь конкретные вопросы про объекты, потом вводишь определение объекта и его идентичности в ответе. Какой смысл в вопросе, если он не подразумевает конкретную систему объектов? Ты ответил не на вопрос "сколько будет выведено объектов", а на вопрос, сколько элементов в списке.
Давай я немного утрирую ситуацию. На вопрос "сколько денег на счету у X" ты отвечаешь "если считать что монеты и купюры одного достоинства идентичны, и являются версиями одной монетой, то ...". Такой ли ответ нужен вопрошающему?
DG>>то получается, что на последующие вопросы невозможно дать определенные ответы, и можно дать лишь ответы с высокой долей неопределенности: S>Можно дать ответы очень определенные. И сколько объектов, и сколько раз каждый.
дай определенные ответы, раз можно
S>Извини, но ты редкий извращенец. Сначала задаешь конкретные вопросы про объекты, потом вводишь определение объекта и его идентичности в ответе. Какой смысл в вопросе, если он не подразумевает конкретную систему объектов? Ты ответил не на вопрос "сколько будет выведено объектов", а на вопрос, сколько элементов в списке.
ты ввел новое понятие "элемент в списке", что это такое и чем это понятие отличается от понятия "ООП-объект"?
S> Какой смысл в вопросе, если он не подразумевает конкретную систему объектов?
при использовании библиотечного кода — пофигу, что именно он считает объектом, главное чтобы гарантировались определенные свойства:
возможность конструирования таких объектов,
возможность внешнего различия,
инвариантность кол-ва,
и т.д.
возьмем все ту же функцию Output, и ее спецификацию — эту функцию можно использовать из произвольного кода? ответ можно, потому что всегда можно взять паттерн адаптер и преобразовать один вид объектов в другой.
спецификация функцию Output:
1. каждая ссылка из items есть ООП-объект (включая null)
2. в качестве object identity берется условная ссылка items[x], где x — это последовательный номер от 0 до items.Count. при этом
объекты, взятые по ссылкам items[x1] и items[x2] считаются разными объектами, если x1 != x2
3. каждый объект будет последовательно выведен на экран с разделителем перевод строки.
можно объекты с ecma-identity преобразовать в объекты с вышеуказанной object idenity? без проблем. даже ничего делать не надо.
S>Давай я немного утрирую ситуацию. На вопрос "сколько денег на счету у X" ты отвечаешь "если считать что монеты и купюры одного достоинства идентичны, и являются версиями одной монетой, то ...". Такой ли ответ нужен вопрошающему?
если этот ответ является более сильным (из него можно сконструировать тот ответ, который необходим вопрошающему), то такого ответа достаточно.
S>Не факт. Может быть выведено 0 объектов при items.Count > 0.
это сложный (с высокой неопределенностью) вопрос, является ли null объектом или не является? в одних случаях его удобно рассматривать, как отсутствие объекта, а в других случаях как вырожденный случай объекта
в данном примере, если рассматривать только вход (список) и выход(строки на экране), и конструируя минимальную спецификацию описывающую что произошло, то приходится сделать вывод, что каждое присутствие null в списке является объектом, который на получение сообщения ToString возвращает пустую строку.
у меня был очень важный вопрос: в каких сценариях реально необходима object identity? когда нам действительно необходимо знать, что объект является одним и тем же?
ответ на этот вопрос, к сожалению, в теме так и не дали, поэтому приходится отвечать самому.
object identity реально необходима лишь при использовании функций, которые меняют объекты. в остальных случаях нет необходимости знать объект является тем же самым или нет.
например, в следующем коде корректность результата работы функции InversePoints (что она инвертирует все переданные точки) можно гарантировать лишь для случая, когда в InversePoints передаются строго различные объекты, и не передается один и тот же объект несколько раз:
class Point
{
public int X;
public int Y;
public void Inverse()
{
X = -X;
Y = -Y;
}
}
public void InversePoints(IEnumerable<Point> points)
{
foreach (var point in points)
point.Inverse();
}
возникает вопрос можно ли даже в таких сценариях избавиться от требования "должны передаваться строго различные объекты", и при этом продолжать обеспечивать гарантии на результат?
ответ — можно, если использовать объекты с immutable-версионностью (причем здесь утверждается, что и функция Inverse и функция InversePoints возвращает те же самые объекты, но измененные, потому что именно в этих терминах можно кратко специфицировать, что эти функции делают).
class Point
{
public Point(int x = 0, int y = 0)
{
this.X = x; this.Y = y;
}
public readonly int X;
public readonly int Y;
public Point Inverse()
{
return new Point(x:-X, y:-Y);
}
}
public IEnumerable<Point> InversePoints(IEnumerable<Point> points)
{
foreach (var point in points)
yield return point.Inverse();
}
данный код не имеет требования, что объекты должны быть строго различны.
при этом сама функция InversePoints считает, что она на вход получает последовательность различных объектов, каждый из которых она инвертирует.
внешний код при этом может иметь и другое мнение, что есть один и тот же объект, но для функции InversePoint это не имеет значения, она все равно будет обеспечивать внятные гарантии на результат.
для первого кода — такое свойство не соблюдалось, там было необходимо, чтобы совпадало мнение — что есть различный объект, как снаружи функции, так и внутри.
ps
данный код может быть так же усилен для варианта, когда null считается вырожденным объектом (и любое изменение такого объекта дает его самого же), при чем даже без изменения самой функции InversePoints
class Point
{
public Point(int x = 0, int y = 0)
{
this.X = x; this.Y = y;
}
public readonly int X;
public readonly int Y;
}
static class PointHlp
{
public static Point Inverse(this Point point)
{
if (point == null)
return null;
return new Point(x:-point.X, y:-point.Y);
}
}
public IEnumerable<Point> InversePoints(IEnumerable<Point> points)
{
foreach (var point in points)
yield return point.Inverse();
}
DG>>>то получается, что на последующие вопросы невозможно дать определенные ответы, и можно дать лишь ответы с высокой долей неопределенности: S>>Можно дать ответы очень определенные. И сколько объектов, и сколько раз каждый.
DG>дай определенные ответы, раз можно
Дай определенную реализацию IList, определенный набор данных, и я тебе дам определенные ответы.
S>>Извини, но ты редкий извращенец. Сначала задаешь конкретные вопросы про объекты, потом вводишь определение объекта и его идентичности в ответе. Какой смысл в вопросе, если он не подразумевает конкретную систему объектов? Ты ответил не на вопрос "сколько будет выведено объектов", а на вопрос, сколько элементов в списке.
DG>ты ввел новое понятие "элемент в списке", что это такое и чем это понятие отличается от понятия "ООП-объект"?
Ты сослался на IList<object> и не поморщился. А теперь спрашиваешь с меня определение понятия, которым пользуется твой код?
S>> Какой смысл в вопросе, если он не подразумевает конкретную систему объектов?
DG>при использовании библиотечного кода — пофигу, что именно он считает объектом, главное чтобы гарантировались определенные свойства: DG>возможность конструирования таких объектов, DG>возможность внешнего различия,
И как ты различаешь свои трассы?
DG>инвариантность кол-ва, DG> и т.д.
DG>возьмем все ту же функцию Output, и ее спецификацию — эту функцию можно использовать из произвольного кода? ответ можно, потому что всегда можно взять паттерн адаптер и преобразовать один вид объектов в другой. DG>спецификация функцию Output: DG>1. каждая ссылка из items есть ООП-объект (включая null) DG>2. в качестве object identity берется условная ссылка items[x], где x — это последовательный номер от 0 до items.Count. при этом DG>объекты, взятые по ссылкам items[x1] и items[x2] считаются разными объектами, если x1 != x2 DG>3. каждый объект будет последовательно выведен на экран с разделителем перевод строки.
DG>можно объекты с ecma-identity преобразовать в объекты с вышеуказанной object idenity? без проблем. даже ничего делать не надо.
А теперь вопрос. А нафига? Ты не можешь сформулировать спецификацию Output в терминах штатной identity и понятий IList?
S>>Давай я немного утрирую ситуацию. На вопрос "сколько денег на счету у X" ты отвечаешь "если считать что монеты и купюры одного достоинства идентичны, и являются версиями одной монетой, то ...". Такой ли ответ нужен вопрошающему?
DG>если этот ответ является более сильным (из него можно сконструировать тот ответ, который необходим вопрошающему), то такого ответа достаточно.
Продемонстрируй как ты из ответа про Output с твоей идентичностью сконструируешь ответ с идентичностью ECMA
Здравствуйте, DarkGray, Вы писали:
S>>Не факт. Может быть выведено 0 объектов при items.Count > 0.
DG>это сложный (с высокой неопределенностью) вопрос, является ли null объектом или не является? в одних случаях его удобно рассматривать, как отсутствие объекта, а в других случаях как вырожденный случай объекта
Можно просто заглянуть в матчасть.
DG>в данном примере, если рассматривать только вход (список) и выход(строки на экране), и конструируя минимальную спецификацию описывающую что произошло, то приходится сделать вывод, что каждое присутствие null в списке является объектом, который на получение сообщения ToString возвращает пустую строку.
Не нужно делать такие выводы. Просто подумай об этом в том ракурсе, что список хранит не объекты а ссылки в случае когда параметризован референс типом.
Здравствуйте, DarkGray, Вы писали:
DG>у меня был очень важный вопрос: в каких сценариях реально необходима object identity? когда нам действительно необходимо знать, что объект является одним и тем же?
DG>ответ на этот вопрос, к сожалению, в теме так и не дали, поэтому приходится отвечать самому.
DG>object identity реально необходима лишь при использовании функций, которые меняют объекты. в остальных случаях нет необходимости знать объект является тем же самым или нет.
Вот те на. А где без identity будет гарантия того что ты посылаешь сообщения одному и тому же объекту? Пусть он иммутабельный, но сообщение может уйти и другому. Как быть с полиморфизмом?
DG>например, в следующем коде корректность результата работы функции InversePoints (что она инвертирует все переданные точки) можно гарантировать лишь для случая, когда в InversePoints передаются строго различные объекты, и не передается один и тот же объект несколько раз: DG>
DG>class Point
DG>{
DG> public int X;
DG> public int Y;
DG> public void Inverse()
DG> {
DG> X = -X;
DG> Y = -Y;
DG> }
DG>}
DG>public void InversePoints(IEnumerable<Point> points)
DG>{
DG> foreach (var point in points)
DG> point.Inverse();
DG>}
DG>
DG>возникает вопрос можно ли даже в таких сценариях избавиться от требования "должны передаваться строго различные объекты", и при этом продолжать обеспечивать гарантии на результат?
Ответ — можно и без immutable. Но ты решил поиграться с identity ради нескольких строчек кода.
DG>ответ — можно, если использовать объекты с immutable-версионностью (причем здесь утверждается, что и функция Inverse и функция InversePoints возвращает те же самые объекты, но измененные, потому что именно в этих терминах можно кратко специфицировать, что эти функции делают).
Ради чего собственно ты утверждаешь что возвращаются те же самые объекты? Функция делает не то что ты утверждаешь, и ты подменил identity с целью втиснуть функцию в спецификацию.
Интересно, а нарушив закон, ты в суде тоже будешь подменять понятия? DG>
DG>public IEnumerable<Point> InversePoints(IEnumerable<Point> points)
DG>{
DG> foreach (var point in points)
DG> yield return point.Inverse();
DG>}
DG>
DG>данный код не имеет требования, что объекты должны быть строго различны. DG>при этом сама функция InversePoints считает, что она на вход получает последовательность различных объектов, каждый из которых она инвертирует. DG>внешний код при этом может иметь и другое мнение, что есть один и тот же объект, но для функции InversePoint это не имеет значения, она все равно будет обеспечивать внятные гарантии на результат.
Если внешний код при этом будет иметь другое мнение на природу объекта, то взаимодействовать с InversePoint он не сможет. Спецификация — она не только для функции. Это контракт на взаимодействие вызывающего кода с вызываемым прежде всего.
DG>для первого кода — такое свойство не соблюдалось, там было необходимо, чтобы совпадало мнение — что есть различный объект, как снаружи функции, так и внутри.
DG>ps DG>данный код может быть так же усилен для варианта, когда null считается вырожденным объектом (и любое изменение такого объекта дает его самого же), при чем даже без изменения самой функции InversePoints
Только это уже не про identity.
S>Вот те на. А где без identity будет гарантия того что ты посылаешь сообщения одному и тому же объекту? Пусть он иммутабельный, но сообщение может уйти и другому.
это гарантия сохраняется в независимости от того, какая object identity выбрана — ecma, ссылочная, версионная и т.д.
S> Как быть с полиморфизмом?
полиморфизм как был так и остается. и примере с null как раз применение полиморфизма и показывает.
или ты на самом деле не знаешь что такое полиморфизм?
DG>>возникает вопрос можно ли даже в таких сценариях избавиться от требования "должны передаваться строго различные объекты", и при этом продолжать обеспечивать гарантии на результат?
S>Ответ — можно и без immutable. Но ты решил поиграться с identity ради нескольких строчек кода.
ты все грозишься что всё можно, а сам еще даже ни одного вывода не сделал, ни строчки кода не привел...
S> Интересно, а нарушив закон, ты в суде тоже будешь подменять понятия?
так ты уже смог показать, что из твоего определения object identity хоть что-то следует?
DG>>ответ — можно, если использовать объекты с immutable-версионностью (причем здесь утверждается, что и функция Inverse и функция InversePoints возвращает те же самые объекты, но измененные, потому что именно в этих терминах можно кратко специфицировать, что эти функции делают). S>Ради чего собственно ты утверждаешь что возвращаются те же самые объекты? Функция делает не то что ты утверждаешь, и ты подменил identity с целью втиснуть функцию в спецификацию.
S>Если внешний код при этом будет иметь другое мнение на природу объекта, то взаимодействовать с InversePoint он не сможет.
сможет, если можно сконструировать адаптер, которую преобразует одну спецификацию в другую.
а в данном случае таким адаптером является тождественное преобразование
DG>>данный код может быть так же усилен для варианта, когда null считается вырожденным объектом (и любое изменение такого объекта дает его самого же), при чем даже без изменения самой функции InversePoints S>Только это уже не про identity.
и опять религиозное мнение без каких-либо выводов из определения.
Здравствуйте, DarkGray, Вы писали: DG>object identity реально необходима лишь при использовании функций, которые меняют объекты. в остальных случаях нет необходимости знать объект является тем же самым или нет.
Совершенно верно. Вот только классическое ООП как раз разработано для объектов, изменяющих своё состояние.
DG>ответ — можно, если использовать объекты с immutable-версионностью
Заумное определение "объекты с immutable-версионностью" можно заменить просто на "immutable объекты".
Ничего плохого в этом нет, просто вы получите существенно другую модель, чем в классическом ООП. Во избежание неконструктивных дискуссий я бы рекомендовал вам воздержаться от называния такой модели объектно-ориентированной. В частности потому, что в такой модели у объектов нет ни идентичности, ни состояния, ни поведения — в тех смыслах, которые вкладываются в эти определения в классическом ООП.
DG>(причем здесь утверждается, что и функция Inverse и функция InversePoints возвращает те же самые объекты, но измененные, потому что именно в этих терминах можно кратко специфицировать, что эти функции делают).
Непонятно, что вы называете "теми же самыми" объектами. Вы только что отказались от identity, которая и была способом отличить "те же самые" объекты от "не тех же самых".
DG>при этом сама функция InversePoints считает, что она на вход получает последовательность различных объектов, каждый из которых она инвертирует.
Нет. Функция InversePoints никак не завязана на различность получаемых объектов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>Вот те на. А где без identity будет гарантия того что ты посылаешь сообщения одному и тому же объекту? Пусть он иммутабельный, но сообщение может уйти и другому.
DG>это гарантия сохраняется в независимости от того, какая object identity выбрана — ecma, ссылочная, версионная и т.д.
Лишь за счет того, что выполняется ecma identity, обеспечивая то, что ссылка ссылается на объект с конкретной identity.
S>> Как быть с полиморфизмом?
DG>полиморфизм как был так и остается. и примере с null как раз применение полиморфизма и показывает.
identity является основой для работы полиморфизма. DG>или ты на самом деле не знаешь что такое полиморфизм?
Твой пример с null показывает что ты не знаешь что такое полиморфизм.
S>>Ответ — можно и без immutable. Но ты решил поиграться с identity ради нескольких строчек кода.
DG>ты все грозишься что всё можно, а сам еще даже ни одного вывода не сделал, ни строчки кода не привел...
Я сделал достаточно выводов относительно твоих определений. И строчки тоже приводил, даже не одну.
Добавь в свой первый вариант Distinct() и каждый объект будет меняться лишь однажды.
S>> Интересно, а нарушив закон, ты в суде тоже будешь подменять понятия?
DG>так ты уже смог показать, что из твоего определения object identity хоть что-то следует?
Ты уже смог показать что из твоих определений не следует что все строки есть один объект, или смирился с этим?
DG>>>ответ — можно, если использовать объекты с immutable-версионностью (причем здесь утверждается, что и функция Inverse и функция InversePoints возвращает те же самые объекты, но измененные, потому что именно в этих терминах можно кратко специфицировать, что эти функции делают). S>>Ради чего собственно ты утверждаешь что возвращаются те же самые объекты? Функция делает не то что ты утверждаешь, и ты подменил identity с целью втиснуть функцию в спецификацию.
S>>Если внешний код при этом будет иметь другое мнение на природу объекта, то взаимодействовать с InversePoint он не сможет.
DG>сможет, если можно сконструировать адаптер, которую преобразует одну спецификацию в другую.
Т.е. ты будешь выдумывать identity под каждую функцию и конструировать адаптеры? Браво. DG>а в данном случае таким адаптером является тождественное преобразование
Тождественное преобразование не является таким адаптером в данном случае. Или ты не знаешь, что такое тождественное преобразование?
DG>>>данный код может быть так же усилен для варианта, когда null считается вырожденным объектом (и любое изменение такого объекта дает его самого же), при чем даже без изменения самой функции InversePoints S>>Только это уже не про identity.
DG>и опять религиозное мнение без каких-либо выводов из определения.
Ты игнорируешь мои выводы. Зачем мне утруждаться?
S>>> Как быть с полиморфизмом?
DG>>полиморфизм как был так и остается. и примере с null как раз применение полиморфизма и показывает. S>identity является основой для работы полиморфизма. DG>>или ты на самом деле не знаешь что такое полиморфизм? S>Твой пример с null показывает что ты не знаешь что такое полиморфизм.
одно из классических определений полиморфизма:
возможность работать одинаковым образом с разнородными объектами.
при этом реализация полиморфизма через vtable, это частный случай реализации полиморфизма.
например, в следующем коде полиморфизм есть — функция Main обрабатывает вывод разнородных объектов (строка, целое число, дробное число) одинаковым образом, но реализация полиморфизма сделана без vtable-а
void Main()
{
foreach (var x in new object[]{"Hello", "world", 37, 21.1})
{
Output(x);
}
}
void Output(object x)
{
if (x is double)
Console.WriteLine("{0,13f2}", x);
if (x is int)
Console.WriteLine("{0,10}", x);
Console.WriteLine(x);
}
для строго наличия наличия полиморфизма или отсутствия полиморфизма — необходимо сначала зафиксировать для какого кода по отношению к какому набору объектов делается утверждение.
следующий код полиморфен для всех объектов, которые реализуют IDisposable, и не полиморфен для набора объектов, которые реализуют IDisposable и не реализуют
var disposable = x as IDisposable;
if (x != null)
disposable.Dispose();
null и полиформизм
следующий код не полиморфен для набора объектов: null и не null, и при наличии такого кода и делается утверждение, что null разрушает полиморфизм
if (point != null)
point.Inverse();
в следующем примере Main полиморфно обрабатывает набор объектов: null и не null.
и null наоборот полиморфизм добавляет, а не разрушает.
void Main()
{
foreach (var p in new Point[]{new Point(x:1, y:2), null, new Point()})
{
p.Inverse();
}
}
static class PointHlp
{
public static void Inverse(this Point p)
{
if (p == null)
return null;
return p._Inverse();
}
}
class Point
{
...
public void _Inverse()
{
..
}
}
S>>>Ответ — можно и без immutable. Но ты решил поиграться с identity ради нескольких строчек кода.
DG>>ты все грозишься что всё можно, а сам еще даже ни одного вывода не сделал, ни строчки кода не привел... S>Я сделал достаточно выводов относительно твоих определений. И строчки тоже приводил, даже не одну. S>Добавь в свой первый вариант Distinct() и каждый объект будет меняться лишь однажды.
согласен будет. только при этом код станет O(n*logn) вместо O(n) и концепция Нулевые побочные затраты, если не используется, пойдут к черту, а так все замечательно.
это я намекаю на то, что определения подбираются такие, чтобы код был хорошим, а не наоборот — подбирается код (в том числе ужасный) под раз зафиксированные определения.
DG>>и опять религиозное мнение без каких-либо выводов из определения. S>Ты игнорируешь мои выводы. Зачем мне утруждаться?
мне лишь не нравится, что ты (не говоря уже про Sinclair-а, который кроме букварей вообще больше ничего не читал) часто используешь закон отрицания третьего, который не работает в конструкционной логике.
а программирование работает в конструкционной логике: потому что интересует возможность реального построения программы из имеющихся ресурсов, а не возможность теоретического существования.
DG>>>и опять религиозное мнение без каких-либо выводов из определения. S>>Ты игнорируешь мои выводы. Зачем мне утруждаться?
DG>мне лишь не нравится, что ты (не говоря уже про Sinclair-а, который кроме букварей вообще больше ничего не читал) часто используешь закон отрицания третьего, который не работает в конструкционной логике. DG>а программирование работает в конструкционной логике: потому что интересует возможность реального построения программы из имеющихся ресурсов, а не возможность теоретического существования.
DG>http://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D0%B8%D0%B2%D0%B8%D0%B7%D0%BC_(%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)
Я почитаю, но попозже.
А пока не было ни одной программы, которую бы я не смог построить из-за отрицания третьего. Кроме того, твои изыски с ООП кажутся мне совершенно необоснованными. Не испытываю никаких сложностей в том что бы использовать идентичность по ECMA при разработке и объяснении своих решений.
S>Понимаешь, не Inverse для списка точек решает какой быть точкой. Решение об иммутабельности точки должно приниматься на более высоком уровне архитектуре, чем подгонка определений для того что бы впихнуть реализацию функции инвертирования списка точек в спецификацию. Функция инвертирования списка точек должна работать с теми точками, с которыми умеет работать вся остальная программа.
библиотечный код пишется в отрыве от самой программы, при этом библиотечный код тем лучше, чем в большем кол-ве различных программ с различными подходами его можно использовать (как напрямую, так и через адаптирующий код).
из этого следует всякие частные требования: например, не использовать static-переменные; "нулевые затраты, если не используется" и т.д.
также известно, что библиотечный код построенный на immutable-объектах можно использовать шире и проще, чем построенный на mutable-объектах, но immutable-объекты более тяжелые для исполнения, чем mutable. при этом последнюю проблему можно ослабить, если используются те или иные техники суперкомпиляции.
S>Код пишется для того, что бы удовлетворить требованиям, а не требования для того что бы удовлетворить коду. Обычно.
это первый шаг.
второй шаг говорит, что требования появляются не ради требования(ради самих себя), а ради лучшего решения задачи
из этого следует третий шаг:
если требования можно сформулировать несколькими способами, то стоит выбрать такую формулировку требований для которой код пишется быстрее, проще, эффективнее и дешевле.
например:
считать null объектом или не считать — это типичное требование, верность которого относительна в зависимости от того при каком подходе получается более лучшее решение.
ты же считаешь что мнение "null — это не объект" — абсолютно(не зависит от контекста), или другими словами догматично, и тебя не интересует будет ли решение при этом лучше или хуже. Тебе лишь важно, чтобы догма "null не объект" сохранялась.
S>Это не лучшее определение лишь одной из частей полиморфизма.
на вики оно ровно такое же
In computer science, polymorphism is a programming language feature that allows values of different data types to be handled using a uniform interface.
особо отмечу, что здесь interface подразумевается в широком смысле, а не в смысле interface основанного на vtable.
DG>>при этом реализация полиморфизма через vtable, это частный случай реализации полиморфизма. S>Не реализации, а вообще, частный случай полиморфизма. Конкретно — subtype полиморфизма. Который есть подвид ad-hoc полиморфизма с разрешением конкретного поведения во время выполнения по первому аргументу.
в целом, вроде согласен.
смущает только середина. что здесь такое subtype? является ли, например, int субтипом double? вообще? и в конкретных языках программирования?
S>Ты смешал в одну кучу параметрический и специальный полиморфизм. в Main null обрабатывается как за счет параметрического, а в Inverce за счет обработки специального случая, но без полиморфизма. Таким образом, null тут таки ломает.
зачем ты лезешь в реализацию?
если бы был язык полностью похожий на C#, но там можно было бы указать для null отдельную vtable со своими реализациями каждой функции, то следующий код был бы полиморфным?
foreach (var p in new Point[]{new Point(), null})
p.Inverse();
DG>>согласен будет. только при этом код станет O(n*logn) вместо O(n) и концепция Нулевые побочные затраты, если не используется, пойдут к черту, а так все замечательно. S>Могу подсказать решение за O(n)
давай
DG>>это я намекаю на то, что определения подбираются такие, чтобы код был хорошим, а не наоборот — подбирается код (в том числе ужасный) под раз зафиксированные определения. S>В этом и проблема, что ты подбираешь определения для того что бы сделать конкретную функцию удовлетворяющей спецификацию, причем рассчитываешь на то что тот кто использует твой код и его определения не совпадают с твоими, будет писать некие адаптеры с ненулевыми побочными затратами.
затраты там почти всегда нулевые, особенно если код подвергается суперкомпиляции
Здравствуйте, DarkGray, Вы писали:
S>>Понимаешь, не Inverse для списка точек решает какой быть точкой. Решение об иммутабельности точки должно приниматься на более высоком уровне архитектуре, чем подгонка определений для того что бы впихнуть реализацию функции инвертирования списка точек в спецификацию. Функция инвертирования списка точек должна работать с теми точками, с которыми умеет работать вся остальная программа.
DG>библиотечный код пишется в отрыве от самой программы, при этом библиотечный код тем лучше, чем в большем кол-ве различных программ с различными подходами его можно использовать (как напрямую, так и через адаптирующий код). DG>из этого следует всякие частные требования: например, не использовать static-переменные; "нулевые затраты, если не используется" и т.д.
Это верно. И определяющим реализацию объекта будет не попытка подогнать реализацию функцию под спецификацию, а более общие соображения.
DG>также известно, что библиотечный код построенный на immutable-объектах можно использовать шире и проще, чем построенный на mutable-объектах, но immutable-объекты более тяжелые для исполнения, чем mutable. при этом последнюю проблему можно ослабить, если используются те или иные техники суперкомпиляции.
Мне это известно. Я широко использую immutable-объекты, но мне не нужно для их использования переопределять идентичность и понятие объекта.
S>>Код пишется для того, что бы удовлетворить требованиям, а не требования для того что бы удовлетворить коду. Обычно.
DG>это первый шаг. DG>второй шаг говорит, что требования появляются не ради требования(ради самих себя), а ради лучшего решения задачи DG>из этого следует третий шаг: DG>если требования можно сформулировать несколькими способами, то стоит выбрать такую формулировку требований для которой код пишется быстрее, проще, эффективнее и дешевле.
Стоит, но только если есть уверенность что заказчик понимает требования точно так же.
DG>например: DG>считать null объектом или не считать — это типичное требование, верность которого относительна в зависимости от того при каком подходе получается более лучшее решение.
Я не вижу как то, считать null объектом или нет, сказывается на решении.
DG>ты же считаешь что мнение "null — это не объект" — абсолютно(не зависит от контекста), или другими словами догматично, и тебя не интересует будет ли решение при этом лучше или хуже. Тебе лишь важно, чтобы догма "null не объект" сохранялась.
Прежде всего, я отличаю объект от ссылки на него. И это мне не мешает, а помогает.
S> Кроме того, твои изыски с ООП кажутся мне совершенно необоснованными. Не испытываю никаких сложностей в том что бы использовать идентичность по ECMA при разработке и объяснении своих решений.
результативность не является достаточным критерием для обоснования хорошести решений. как минимум еще выделяют эффективность, экономичность, экологичность. на следующий уровнях еще больше плоскостей выделяется.
Здравствуйте, DarkGray, Вы писали:
S>>Это не лучшее определение лишь одной из частей полиморфизма.
DG>на вики оно ровно такое же DG>
DG>In computer science, polymorphism is a programming language feature that allows values of different data types to be handled using a uniform interface.
DG>особо отмечу, что здесь interface подразумевается в широком смысле, а не в смысле interface основанного на vtable.
Я знаю. Твое мне не понравилось тем, что там было сказано "одинаковым образом", в то время как специальный полиморфизм подразумевает "разным образом". Uniform interface — это корректно.
DG>>>при этом реализация полиморфизма через vtable, это частный случай реализации полиморфизма. S>>Не реализации, а вообще, частный случай полиморфизма. Конкретно — subtype полиморфизма. Который есть подвид ad-hoc полиморфизма с разрешением конкретного поведения во время выполнения по первому аргументу.
DG>в целом, вроде согласен. DG>смущает только середина. что здесь такое subtype? является ли, например, int субтипом double? вообще? и в конкретных языках программирования?
так ты сходи по ссылочке из вики.
S>>Ты смешал в одну кучу параметрический и специальный полиморфизм. в Main null обрабатывается как за счет параметрического, а в Inverce за счет обработки специального случая, но без полиморфизма. Таким образом, null тут таки ломает.
DG>зачем ты лезешь в реализацию? DG>если бы был язык полностью похожий на C#, но там можно было бы указать для null отдельную vtable со своими реализациями каждой функции, то следующий код был бы полиморфным? DG>
DG>foreach (var p in new Point[]{new Point(), null})
DG> p.Inverse();
DG>
Зачем выдумывать язык для NullObject?
Этот код не полиморфен. null здесь не абстрактный null. Это значение типа ссылка на Point. Здесь в цикле ты работаешь с одним единственным типом — Point. Потому по определению никакого полиморфизма не будет. Если, конечно твой null-объект не окажется унаследованным от Point...
DG>>>согласен будет. только при этом код станет O(n*logn) вместо O(n) и концепция Нулевые побочные затраты, если не используется, пойдут к черту, а так все замечательно. S>>Могу подсказать решение за O(n)
DG>давай
сделать глубокую копию списка поинтов, инвертировать поинты в нем, потом перенести изменения на поинты исходного списка.
DG>>>это я намекаю на то, что определения подбираются такие, чтобы код был хорошим, а не наоборот — подбирается код (в том числе ужасный) под раз зафиксированные определения. S>>В этом и проблема, что ты подбираешь определения для того что бы сделать конкретную функцию удовлетворяющей спецификацию, причем рассчитываешь на то что тот кто использует твой код и его определения не совпадают с твоими, будет писать некие адаптеры с ненулевыми побочными затратами.
DG>затраты там почти всегда нулевые, особенно если код подвергается суперкомпиляции
Ты надеешься что суперкомпиляция сможет нарисовать код, который с нулевыми затратами будет преобразовывать мутабельные поинты в иммутабельные и обратно после инвертирования иммутабельных?
S>> Кроме того, твои изыски с ООП кажутся мне совершенно необоснованными. Не испытываю никаких сложностей в том что бы использовать идентичность по ECMA при разработке и объяснении своих решений.
DG>результативность не является достаточным критерием для обоснования хорошести решений. как минимум еще выделяют эффективность, экономичность, экологичность. на следующий уровнях еще больше плоскостей выделяется.
Есть решение, записанное в коде. До такого же решения (по крайней мере с инвертированием точек) я могу дойти не извращая ООП. А если я дойду до него не извращая ООП, значит оно окажется столь же эффективным и даже экологичным. Так нафига ломать себе голову?
Покажи преимущества, которые недостижимы с штатной идентичностью...
S>Мне это известно. Я широко использую immutable-объекты, но мне не нужно для их использования переопределять идентичность и понятие объекта.
в том числе и при использовании суперкомпиляции?
если immutable-объект не является объектом (не является эквивалентым объекту), то почему тогда при суперкомпиляции его можно преобразовывать в mutable-объекты?
S>Стоит, но только если есть уверенность что заказчик понимает требования точно так же.
что-то мне подсказывает, что заказчику пофигу, считается null — объектом или нет.
это чисто твоя догма, а не заказчика.
DG>>например: DG>>считать null объектом или не считать — это типичное требование, верность которого относительна в зависимости от того при каком подходе получается более лучшее решение. S>Я не вижу как то, считать null объектом или нет, сказывается на решении.
если считать, что для хорошего кода доказывается его корректность (хотя бы не явно), что делается через спецификации, а когда null не считается объектом, то спецификации получаются более раздутыми, что исходя из ограниченности ресурсов, приводит к тому, что корректность программы доказывается в намного меньших масштабах
DG>>ты же считаешь что мнение "null — это не объект" — абсолютно(не зависит от контекста), или другими словами догматично, и тебя не интересует будет ли решение при этом лучше или хуже. Тебе лишь важно, чтобы догма "null не объект" сохранялась. S>Прежде всего, я отличаю объект от ссылки на него. И это мне не мешает, а помогает.
примеры кода, пожалуйста, на которых видно обоснованность данного вывода.
Здравствуйте, DarkGray, Вы писали:
S>>Мне это известно. Я широко использую immutable-объекты, но мне не нужно для их использования переопределять идентичность и понятие объекта.
DG>в том числе и при использовании суперкомпиляции?
Суперкомпиляцию я не использую DG>если immutable-объект не является объектом (не является эквивалентым объекту), то почему тогда при суперкомпиляции его можно преобразовывать в mutable-объекты?
А почему immutable не является объектом?
И почему суперкомпиляция должна преобразовывать его в mutable объект?
Ты хочешь сказать, что по коду инвертирования списка иммутабельных точек суперкомпиляция сделает код инвертирования мутабельных точек? С чего бы?
S>>Стоит, но только если есть уверенность что заказчик понимает требования точно так же.
DG>что-то мне подсказывает, что заказчику пофигу, считается null — объектом или нет. DG>это чисто твоя догма, а не заказчика.
А вот иммутабельна точка или нет — может быть не пофигу.
S>>Я не вижу как то, считать null объектом или нет, сказывается на решении.
DG>если считать, что для хорошего кода доказывается его корректность (хотя бы не явно), что делается через спецификации, а когда null не считается объектом, то спецификации получаются более раздутыми, что исходя из ограниченности ресурсов, приводит к тому, что корректность программы доказывается в намного меньших масштабах
Поменьше используй null-ы будет тебе спецификация с доказательствами покороче.
DG>>>ты же считаешь что мнение "null — это не объект" — абсолютно(не зависит от контекста), или другими словами догматично, и тебя не интересует будет ли решение при этом лучше или хуже. Тебе лишь важно, чтобы догма "null не объект" сохранялась. S>>Прежде всего, я отличаю объект от ссылки на него. И это мне не мешает, а помогает.
DG>примеры кода, пожалуйста, на которых видно обоснованность данного вывода.
Примеры кода, которые показывают как мне это помогает? Это субъективно. На уровне мух и котлет. Кому-то нравится, но не мне.
DG>>в целом, вроде согласен. DG>>смущает только середина. что здесь такое subtype? является ли, например, int субтипом double? вообще? и в конкретных языках программирования? S>так ты сходи по ссылочке из вики.
NullObject как раз под это определение подходит, а NullObject в зависимости от договоренностей и возможностей языка может реализовываться и через null
S>Зачем выдумывать язык для NullObject?
потому что это отдельный subtype, требующий отдельного описания.
S>Этот код не полиморфен. null здесь не абстрактный null.
с точки зрения выделения subtype — это не требуется.
также не требуется, что subtype (и type) соответствовали типам из ЯП на котором реализуется программа.
S> Это значение типа ссылка на Point. Здесь в цикле ты работаешь с одним единственным типом — Point. Потому по определению никакого полиморфизма не будет. Если, конечно твой null-объект не окажется унаследованным от Point...
когда я пытаюсь сформировать видение твоего мировозрения, то у меня появляется чувство диссонанса.
1. с одной стороны, ты вроде понимаешь, что абстрактные (как концепции) type, subtype, object, полиморфизм и т.д. существуют в коде в независимости от того, как в ЯП реализованы их конкретные аналоги, и что при этом отношения между абстрактными и конкретными аналогами не 1 к 1.
2. с другой стороны, утверждения ты часто строишь по схеме — в моем любимом языке конкретная реализация подразумевает то и то, из этого следует, что в моем любимом языке тоже самое следует и для абстрактных type, subtype, object и т.д.
S>сделать глубокую копию списка поинтов, инвертировать поинты в нем, потом перенести изменения на поинты исходного списка.
S> потом перенести изменения на поинты исходного списка
как вот это будет делаться за O(n), и какой алгоритм будет использоваться для понимания, какой immutable-объект из результата какому mutable-объекту соответствует? в частности для тех же point-ов
S>Ты надеешься что суперкомпиляция сможет нарисовать код, который с нулевыми затратами будет преобразовывать мутабельные поинты в иммутабельные и обратно после инвертирования иммутабельных?
суперкомпиляция, как минимум, на основе immutable-кода может построить его inplace-версию кода поверх mutable-объектов, и такой код имеет нулевые затраты.
напомню, что под immutable-объектом я понимал объект с immutable-версионностью, и что операции изменяющие immutable-объект выдают тот же самый объект
S>И почему суперкомпиляция должна преобразовывать его в mutable объект?
это желательное требование, потому что inplace реализации поверх mutable-объектов обеспечивают бОльшую вычислительную эффективность.
S>Ты хочешь сказать, что по коду инвертирования списка иммутабельных точек суперкомпиляция сделает код инвертирования мутабельных точек? С чего бы?
если поставлена задача обеспечить максимальную эффективность, то сделает.
DG>>примеры кода, пожалуйста, на которых видно обоснованность данного вывода. S>Примеры кода, которые показывают как мне это помогает? Это субъективно. На уровне мух и котлет. Кому-то нравится, но не мне.
и соответственно, целиком утверждение которое ты остаиваешь в этот треде выглядит как?:
мне лично субъективно не нравится когда не различают ссылки и объекты, поэтому я тебе запрещаю говорить на форуме, что "можно быстро разрабатывать эффективные и простые программы и не различать при этом ссылки и объекты".
ты согласен с такой формулировкой?
S>Покажи преимущества, которые недостижимы с штатной идентичностью...
хотя бы разработка полноценного редактора схем (фигурки + связи) поверх трехзвенки: БД, web-сервер и браузер.
если использовать штатную идентичность, это как минимум потребует написания трех вариантов кода для написания одного и того же, но для различных сред исполнения: sql, серверный ЯП, js, как минимум из-за того, что на основе кода со штаной идентичностью геморройно создается аналогичный код для других языков, распределенного контекста и т.д.
Здравствуйте, DarkGray, Вы писали:
S>>А почему immutable не является объектом?
DG>это надо тебя спросить.
Я такого не утвреждал. Sinclair?
DG>напомню, что под immutable-объектом я понимал объект с immutable-версионностью, и что операции изменяющие immutable-объект выдают тот же самый объект
Я под иммутабл объектом понимаю прежде всего объект (с нормальной такой идентичностью), который ведет себя так, что никаких изменений в его поведении не может быть обнаружено извне.
S>>И почему суперкомпиляция должна преобразовывать его в mutable объект?
DG>это желательное требование, потому что inplace реализации поверх mutable-объектов обеспечивают бОльшую вычислительную эффективность.
Может ты покажешь такое преобразование кода, которое могла бы выполнить суперкомпиляция. Желательно с нулевыми затратами на выполнение инверсии.
S>>Ты хочешь сказать, что по коду инвертирования списка иммутабельных точек суперкомпиляция сделает код инвертирования мутабельных точек? С чего бы?
DG>если поставлена задача обеспечить максимальную эффективность, то сделает.
Покажи
DG>>>примеры кода, пожалуйста, на которых видно обоснованность данного вывода. S>>Примеры кода, которые показывают как мне это помогает? Это субъективно. На уровне мух и котлет. Кому-то нравится, но не мне.
DG>и соответственно, целиком утверждение которое ты остаиваешь в этот треде выглядит как?: DG>мне лично субъективно не нравится когда не различают ссылки и объекты, поэтому я тебе запрещаю говорить на форуме, что "можно быстро разрабатывать эффективные и простые программы и не различать при этом ссылки и объекты". DG>ты согласен с такой формулировкой?
Я утверждаю что разрабатывать эффективные и простые программы можно и не путая ссылки и объекты. Но можно и путая, чего я запрещать не собираюсь. Я только не понимаю, зачем их надо путать?
S>>Покажи преимущества, которые недостижимы с штатной идентичностью...
DG>хотя бы разработка полноценного редактора схем (фигурки + связи) поверх трехзвенки: БД, web-сервер и браузер. DG>если использовать штатную идентичность, это как минимум потребует написания трех вариантов кода для написания одного и того же, но для различных сред исполнения: sql, серверный ЯП, js, как минимум из-за того, что на основе кода со штаной идентичностью геморройно создается аналогичный код для других языков, распределенного контекста и т.д.
Вот беда. Ради трехзвенки тебе нужно обязательно ломать идентичность? Что мешает использовать отношение послабже, например эквивалентность по ключу?
S>var list1 = list.Select(p => new Point(p.x, p,y)).ToList();
S>for (int i = 0; i < list.Count; i++)
S>{
S> var p = list1[i];
S> p.Inverse();
S> list[i].x = p.x;
S> list[i].y = p.y;
S>}
S>
при этом для обоснования корректности, ты используешь то, что:
объект list[i] переходит в объект list1[i], который переходит в условный p[i], далее p_измененный[i], и затем опять list[i].
и обоснование, что изменение получит именно тот объект, для которого они и предназначались строится через доказательство корректности преобразований над ссылками, а не над самими объектами.
переход list[i] -> list1[i] -> p[i] -> p_измененный[i] -> list[i] — это и есть трасса.
S>>>Ты надеешься что суперкомпиляция сможет нарисовать код, который с нулевыми затратами будет преобразовывать мутабельные поинты в иммутабельные и обратно после инвертирования иммутабельных?
DG>>суперкомпиляция, как минимум, на основе immutable-кода может построить его inplace-версию кода поверх mutable-объектов, и такой код имеет нулевые затраты. S>Если не в лом, покажи мне код после суперкомпиляции. Хотя бы то, как мог бы выглядеть его аналог с мутабл объектами.
все сильно зависит от того, насколько сильные предусловия сможет доказать суперкомпилятор для точек, которые передаются в InversePoints, в частности интересует кол-во использований и способ использования результата и входа.
для InversePoints можно построить как минимум следующие оптимизированные версии в дополнение к immutable-варианту
(ienumerable раскрывается в массив, как в самую быструю штуку в .net-е, при необходимости может появляться slice-версия (points, start_index, count) и т.д.):
void InversePoints_Inplace(this S_Point[] points)
{
for (int i = 0; i < points.Length; ++i)
{
p[i].X = -p[i].X;
p[i].Y = -p[i].Y;
}
}
struct S_Point
{
public int X;
public int Y;
...
}
class Point
{
public int X;
public int Y;
public Point Inverse()
{
return new Point{X = X, Y = Y};
}
public void Inverse_Inplace()
{
X = -X;
Y = -Y;
}
}
//используется только если компилятор может доказать, что все исходные point-ы различныеvoid InverseDifferentPoints_Inplace(this Point[] points)
{
for (int i = 0; i < points.Length; ++i)
{
p[i].X = -p[i].X;
p[i].Y = -p[i].Y;
}
}
void InversePoints_Inplace(this Point[] points)
{
var _points = new S_Point[points.Length];
for(int i = 0; i < points.Length; ++i)
{
_points[i].X = -points[i].X;
_points[i].Y = -points[i].Y;
}
for(int i = 0; i < points.Length; ++i)
{
points[i].X = _points[i].X;
points[i].Y = _points[i].Y;
}
}
Здравствуйте, DarkGray, Вы писали:
S>>Тривиально S>>
S>>var list1 = list.Select(p => new Point(p.x, p,y)).ToList();
S>>for (int i = 0; i < list.Count; i++)
S>>{
S>> var p = list1[i];
S>> p.Inverse();
S>> list[i].x = p.x;
S>> list[i].y = p.y;
S>>}
S>>
DG>при этом для обоснования корректности, ты используешь то, что: DG>объект list[i] переходит в объект list1[i], который переходит в условный p[i], далее p_измененный[i], и затем опять list[i].
Ничто никуда не переходит. Объект list[i] остается самим собой. Объект list1[i] с list[i] никак не связан, кроме того что получен с использованием значений полей объекта list[i]. Больше их ничего не связывает.
DG>и обоснование, что изменение получит именно тот объект, для которого они и предназначались строится через доказательство корректности преобразований над ссылками, а не над самими объектами.
Оно строится через порядковые места в списках.
DG>переход list[i] -> list1[i] -> p[i] -> p_измененный[i] -> list[i] — это и есть трасса.
Нет никакой трассы.
DG>>>суперкомпиляция, как минимум, на основе immutable-кода может построить его inplace-версию кода поверх mutable-объектов, и такой код имеет нулевые затраты. S>>Если не в лом, покажи мне код после суперкомпиляции. Хотя бы то, как мог бы выглядеть его аналог с мутабл объектами.
DG>все сильно зависит от того, насколько сильные предусловия сможет доказать суперкомпилятор для точек, которые передаются в InversePoints, в частности интересует кол-во использований и способ использования результата и входа.
Ты сам сказал, что это библиотечный метод.
DG>для InversePoints можно построить как минимум следующие оптимизированные версии в дополнение к immutable-варианту DG>(ienumerable раскрывается в массив, как в самую быструю штуку в .net-е, при необходимости может появляться slice-версия (points, start_index, count) и т.д.): DG>
DG>void InversePoints_Inplace(this S_Point[] points)
DG>{
DG> for (int i = 0; i < points.Length; ++i)
DG> {
DG> p[i].X = -p[i].X;
DG> p[i].Y = -p[i].Y;
DG> }
DG>}
Это не работает для повторяющихся экземпляров. Суперкомпилятор не знает, будут ли они повторяться. Это библиотечный метод
DG>//используется только если компилятор может доказать, что все исходные point-ы различные
Как он может доказать что все поинты различные, если метод библиотечный?
Ты вообще о какой библиотеке говорил? Об dll или о библиотеке исходных кодов для суперкомпиляции?
S>>Вот беда. Ради трехзвенки тебе нужно обязательно ломать идентичность? Что мешает использовать отношение послабже, например эквивалентность по ключу?
DG>если то, что крякает, плавает и ныряет как утка назвать утка-штрих, то это лишь добавит головной боли для поддержки и ничего более...
Головной боли добавляет твоя идентичность с трассами, а не штрихи
Здравствуйте, DarkGray, Вы писали:
DG>>>и опять религиозное мнение без каких-либо выводов из определения. S>>Ты игнорируешь мои выводы. Зачем мне утруждаться?
DG>мне лишь не нравится, что ты (не говоря уже про Sinclair-а, который кроме букварей вообще больше ничего не читал) часто используешь закон отрицания третьего, который не работает в конструкционной логике.
Прочитал ссылочку про конструктивную математику, теперь отвечу развернуто.
Во-первых — я считаю что Sinclair читал достаточно много, и по субъективным впечатлениям значительно больше меня, а главное, с большим толком. Во-вторых, я считаю что Sinclair достаточно глубоко понимает материал, раскладывает его по полочкам, очень четко выделяет абстракции и их уровни.
DG>а программирование работает в конструкционной логике: потому что интересует возможность реального построения программы из имеющихся ресурсов, а не возможность теоретического существования.
DG>http://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BD%D1%81%D1%82%D1%80%D1%83%D0%BA%D1%82%D0%B8%D0%B2%D0%B8%D0%B7%D0%BC_(%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D0%BA%D0%B0)
Да, существуют объективные причины не считать объекты вечноживущими и пользоваться ограниченным представлением вещественных чисел. Но какие причины для отказа от идентичности в пользу трасс? Причем тут вообще идентичность? Нужна история преобразований объекта — пожалуйста. Версии — отлично. Но без ломания ООП. Чем тебе мешает отличать 2 версии друг от друга по правилам ООП?
То что в программе существует множество объектов, описывающих состояние одной моделируемой сущности в "жизни" — это нормальная ситуация. Считай их журналом. Если мы у больного будем мерить температуру и записывать в тетрадочку, больной от этого не размножится по числу записей, описывающих его состояние!
В общем, я не понимаю. Я могу спокойно думать об иммутабельных объектах как о самостоятельных объектах ООП и у меня от этого не болит голова, как от твоих трасс с затейливой идентичностью.
А приведение типа у тебя так же сохраняет идентичность приведенного с приводимым?
DG>>void InversePoints_Inplace(this S_Point[] points)
DG>>{
DG>> for (int i = 0; i < points.Length; ++i)
DG>> {
DG>> p[i].X = -p[i].X;
DG>> p[i].Y = -p[i].Y;
DG>> }
DG>>}
S>
S>Это не работает для повторяющихся экземпляров. Суперкомпилятор не знает, будут ли они повторяться. Это библиотечный метод
во-первых, S_Point — это структура, поэтому нет проблемы с повторяющимися экземплярами.
во-вторых, при суперкомпиляции библиотеки и не требуется знание будет повторяться или нет. это задача суперкомпиляции конечного кода.
DG>>>void InversePoints_Inplace(this S_Point[] points)
DG>>>{
DG>>> for (int i = 0; i < points.Length; ++i)
DG>>> {
DG>>> p[i].X = -p[i].X;
DG>>> p[i].Y = -p[i].Y;
DG>>> }
DG>>>}
S>>
S>>Это не работает для повторяющихся экземпляров. Суперкомпилятор не знает, будут ли они повторяться. Это библиотечный метод
DG>во-первых, S_Point — это структура, поэтому нет проблемы с повторяющимися экземплярами.
То что это структура — я упустил.
DG>во-вторых, при суперкомпиляции библиотеки и не требуется знание будет повторяться или нет. это задача суперкомпиляции конечного кода.
Окей. Так причем тут трассы? Вся работа кода выражается в терминах преобразования и переноса данных без изменения identity.
V>Императивное программирование — технология программирования, характеризующаяся принципом последовательного изменения состояния вычислителя пошаговым образом.
Ну вот видите, как вы начинаете подтверждать то, что я вам рассказываю. В РА нет никакого последовательного изменения состояния вычислителя.
V>Мммм, это должно сойти за док-во, что для конкретной формулы РА порядок вычислений и прочее не важно, не так ли?
Это должно сойти за доказательство того, что РА не навязывает порядок вычислений.
V>В итоге, какой бы конкретный вид формулы ты не выбрал для программирования, для нее будет важен порядок вычисления промежуточных аргументов с т.з. их последующего применения именно в этом варианте твоей формулы, пусть даже после 100500 преобразований от предполагаемой исходной формулы.
Вы передёргиваете. Да, то, что исполняется реальным query engine — на 100% императивная программа. Там есть вычислитель, есть его состояние. Но между исходной формулой РА и реальным вычислением — бездна. Точно так же я могу сказать, что начав с предиката в РИ я всё равно приду к тому или иному виду физического плана исполнения запроса. Это ничего не говорит о том, что РИ само по себе сколь-нибудь императивно.
V>Ты ведь пока не понимаешь и 50% от того, что говорю, коль приводишь как аргумент такие страницы. Специально переспросил у бывшего одногруппника, с которым поддерживаю связь — он с полуслова понял о чем речь, в отличие от. И я прекрасно вижу — почему. На голой эрудиции так далеко уехать уже не получается, надо или попытаться освоить раздел самостоятельно, или внимать коллегам.
Пока я не вижу у вас ни позитивных результатов самостоятельного освоения раздела, ни готовности внимать коллегам.
V>Остальное идет как контекст. Так вот, для случая кластерного индекса на странице содержится вся строка таблицы, т.е. на каждой странице будет меньше значений ключа, поэтому с т.з. быстродействия именно кластерного индекса, чем 'уже (в байтах) таблица, т.е. чем больше записей на каждой странице, тем шустрее поиск по этому ключу. Меньше потребуется просмотреть страниц в случае какого-нить двоичного поиска.
А, я понял, в чём ваше заблуждение. Вы не понимаете, чем leaf pages кластерного индекса отличаются от non-leaf pages, и поэтому путаете размер ключа кластерного индекса с размером всей таблицы. Для "двоичного поиска" (которым вы, судя по всему, называете операцию index seek) в кластерном индексе конечно же не нужно просматривать "больше" страниц. Точно также просматривается logN.
Вы бы сразу спросили, если в Books Online непонятно написано.
V>Общий физический размер данных таблицы играет роль для принятия решения — делать уникальный ключ кластерным или нет (для неуникальных индексов кластерный работает хорошо, чуть ниже пройдусь по этой теме). Если кол-во данных в таблице относительно мало, а таблица частоиспользуема, то вполне пойдет кластерный индекс даже для случая, когда строки таблицы относительно широкие. Если вернешься назад, именно об этом с самого начала шла речь, я малость удивляюсь, почему это требуется объяснять.
Я три поста назад подробно объяснил, по каким критериям выбирается кластерный индекс. Общий размер данных и ширина таблицы никакого значения не имеют. Если вам это непонятно, то почитайте литературу или спросите.
V>Нет, не все-равно, т.к. данные хранятся вместе с ключами.
Нет, не хранятся. Учите матчасть.
V>Это есть объяснение работы кластерного индекса?
Нет, это мы сейчас ваши заблуждения будем исправлять. V>Кстати, подходящий пример. Если размер таблицы относительно мал, то кластерный индекс по passportNumber вполне покатит, но если же во много раз больше размеров ОП, то кластерный будет существенно сливать некластерному по тому же полю при выборе одиночных значений.
Ок, пусть таблица во много раз больше "размеров ОП". Вот мы делаем запрос
select * from Person where PassportNumber = @number
Вы всерьёз полагаете, что кластерный индекс по PassportNumber покажет худшую производительность, чем некластерный? Тогда вам ещё много нового предстоит узнать.
V>Давай так, если в MS SQL 2003 и выше что-то кардинально изменилось в плане кластерных индексов,
Да нет, не изменилось. Всё точно так же, как и было в MS SQL Server 7.0. V>то так и быть, потрачу время на изучение и признаю неправоту (если хотя бы в двух словах обрисуешь, что именно поменялось в плане кластерных индексов). Потому как линейка от 6-ки до MS SQL 2000 была в своё время изучена настолько подробно, насколько это вообще возможно, включая местами исходники.
Исходники? Зачем вам могли понадобиться исходники?
Достаточно штатных инструментов из поставки сервера.
V>Отличный вопрос. Как раз подтверждает мои кое-какие подозрения. Иначе я не могу объяснить, откуда в тебе уверенность, что от размера таблицы и от относительной ширины не зависит сравнительная эффективность одного и того же индекса для случая выполнения его как кластерного или некластерного. Я не знаю, где именно ты лазил, но тестов на производительность ты точно не делал, бо там нехилую разницу легко получить, как раз на твоем примере с passportNumber, и спорить сразу станет не о чем. Еще же можно включить трейс и тупо посмотреть на кол-во сканированных страниц, наконец, для каждого из случаев. Если для некластерного у меня получалось получалось 1-2 страницы, для не самой большой таблицы, то для случае этого же индекса как кластерного — легко десяток-полтора сканированных страниц ради одного значения.
Вы неубедительно врёте. Полтора десятка страниц для индекса, что кластерного, что нет — это нужна очень большая таблица.
Ок, давайте поставим Решаюший Эксперимент.
У вас есть под рукой osql.exe?
Запустите в нём вот такой вот несложный скрипт:
create database TestDB;
GO
use TestDB;
GO
CREATE TABLE [dbo].[Test]
(
id int identity primary key,
key1 uniqueidentifier constraint key1 unique clustered,
key2 uniqueidentifier constraint key2 unique nonclustered,
padding char(7950) not null default ''
)
GO
CREATE PROCEDURE [dbo].[Initialize]
@size int
AS
set nocount on;
delete from Test;
declare @i int;
set @i = 0;
while @i< @size
begin
declare @key uniqueidentifier;
set @key = NEWID();
insert into Test(key1, key2) values(@key, @key);
set @i = @i + 1;
end
RETURN 0
GO
set nocount on
declare @pageCount int
set @pageCount = 10 -- укажите здесь количество страниц, которые вы хотите поместить в эту таблицу exec Initialize @pageCount
declare @testid uniqueidentifier
select @testid = key1 from Test where id = cast(round(RAND()*@pageCount , 0, 0) as int)
set statistics io on
select id from Test where key1 = @testid; -- кластерныйselect id from Test where key2 = @testid; -- некластерный
GO
use master
drop database TestDB
Если что-то непонятно — спрашивайте.
Можете предсказать количество logical reads для случаев pageCount = 1, 10, 100, 1000, 10000?
V>А можно по-русски? Бо индексы бывают еще и неуникальные, т.е. могут не быть альтернативным ключом.
Ключ индекса — выражение, составленное из столбцов таблицы, которое будет включаться в индекс.
S>>Потому что на практике каноничность не интересна. Откройте произвольное приложение, которое работает с базой данных, и поищите, сколько раз встречается select, а сколько раз distinct. Это даст вам примерное представление о доле "РА-совместимых" запросов в типичном SQL.
V>Сорри, но это уже вовсе безграмотно... Зачем мне distinct при выборе уникальных значений из базы в 3-й НФ? Этот distinct мы уже сократили в уме.
Вы-то сократили, а SQL — нет, не сократил. V>А если неуникальные, т.е. не включающие ключи, — то они как раз выбираются для групповых операций, в т.ч. чтобы по ним специально сделать потом distinct.
Ключевое слово — потом.
V>Поэтому вопрос таки в силе, показать пример реального магазина или склада какого-нить, где действительно нужно гнать на клиента последовательность повторяющихся данных без групповых операций над ними.
Я ничего не говорил про "гнать на клиента". Читайте то, что вам пишут, а не то, что вы себе придумываете.
V>А конкретное что-то есть, кроме общих фраз?
Конкретно — отсутствие дубликатов, двузначная логика.
V>Да просто сколько SQL-ей видел, столько раз их заново надо учить, это фактически другие языки, область пересечения диалектов ничтожна, буквально по самым простеньким запросам.
Прекратите позориться. Есть большое количество кросс-СУБД проектов. Область пересчения диалектов значительно шире, чем чистый SQL-92.
V>>>Читал, давно и многократно. Давай конкретную фразу/абзац/не_важно_что, которые должны что-то такое доказать. V>Итого, в терминах двоичной логики решение принимается так: WHERE <search condition> IS TRUE. Это и есть boolean test. Заметь, не сравнение <search condition> = TRUE, а именно тест IS TRUE.
Это я и пытаюсь объяснить уже два поста. См. мой пример с юнионом двух селектов.
V>Это гребанный стыд уже...
Да я вижу. Вы никому не говорите, где учились, а то опозорите свой ВУЗ.
V>NOT — это ключевое слово языка, который разрабатывался чтобы быть максимально близким к человеческому английскому.
NOT в данном контексте — это унарная функция, которая реализует в SQL операцию логического отрицания. Ваш К.О. V>А что означает NOT в выражении: <expression> IS NOT NULL?
Здесь это слово — часть оператора "IS NOT NULL". Конкретно этот оператор никогда не возвращает UNKNOWN.
Никакого отношения к унарной логической функции NOT это не имеет. Чтобы два раза не вставать: Есть ещё NOT BETWEEN, NOT LIKE, и NOT IN.
Кстати, об IS NOT NULL: выражение R IS NOT NULL не эквивалентно выражению NOT R IS NULL.
V>Таблица истинности для NOT расписана, эта операция определена в языке SQL над доменом {true, false, null}.
Вообще-то {true, false, unknown}. V>Но! boolean test производится не над каждой операцией в выражении, а над результатом всего выражения, каким бы составным оно не было.
И каким образом это опровергает что-то из того, что я сказал?
V>Тю, у MS SQL есть, а у MS Access уже нет. В общем, мне эта тема неинтересна, бо она по-факту малопоследовательна, глядя на мн-во реализаций SQL в различных СУБД, чтобы делать какие-то выводы.
Вы сначала разберитесь в основах, а потом будете делать какие-то выводы.
V>это элементарно.
Удивляет только то, что вы до сих пор не знаете этих общеизвестных фактов из SQL, и мне приходится мучительно их объяснять.
V>В общем, если в ограничения целостности не вбили какое-то правило, то это чаще всего по соображениям эффективности, чтобы сервер не строил ненужный индекс и не делал на каждый чих лишние проверки, а не потому что такого ограничения в предметной области нет.
Ну вот видите — через три поста вы таки понимаете, о чём я говорю. Да, уникальность не вбили в SQL по соображениям эффективности.
V>Угу, осталось сделать всего один шаг и понять, что может кардинальное отличаться терминология в разных предметных областях. Т.е. одни и те же термины в разных координатах могут означать совсем разные понятия и вполне уместен некий перевод одних терминов в другие при переходе из одной модели в другую.
Ну вот видите, как здорово. А ещё на прошлой неделе вам и в голову бы не пришло, что предикат в РА и предикат в SQL вообще могут означать разные понятия.
V>Давай так. Ты еще ничего не обяснил. НИЧЕГО. Технические объяснения должны быть верифицируемы, а твой основной аргумент выглядит так: "вы неверно это себе представляете", что невозможно верифицировать.
Почему? Возможно. Я даю вам задачу, вы её решаете. Если понимаете правильно — ответ совпадает. Если неправильно — ответ не совпадает.
V>Тоже самое касательно ограничений. Я 10-й раз прошу (и знаю, почему) придумать пример, где действительно НАДО выходить за рамки реляционной теории в реальных БД.
Я вам привёл пример выше по топику. Встречный вопрос: зачем создатели SQL так мучились, вводя поддержку мультисетов в язык, если нигде в реальных примерах не нужно выходить за рамки реляционной модели?
V>У меня такое случалось и я знаю когда я это делал — это когда БД исопльзовалась не как реляционнное хранилище.Именно это я собирался продемоснтрировать на абсолютно любом приведенном примере, иначе бы он был сведен к вполне помещающемся в рамки наработок реляционной теории. Обсуждать технические решения вообще интересно само по себе, в отличие от гаданий, насколько "монолитно" (С) что-то у кого-то в голове. Это к мозгоправу, а не сюда.
Мы находимся в форуме, посвящённом мозгоправлению. А я в данный момент играю роль мозгоправа.
V>Приехали... договорились... Да какую бы я реализацию реляционной модели не взял, она будет отличаться от реляционной модели хотя бы потому, что реляционная модель никак не ограничивает свою реализацию. Не понимаешь? Изначально подробностями реализации пренебрегли. Есть, конечно, кое-какие практические наработки и исследования стоимостей операций при разных способах хранения данных, но это сугубо инженерные исследования в конкретных, с т.з. инженерии, условиях, никак не связанных, разумеется, с теорией.
С какой именно теорией? Прочтите учебник по разработке СУБД. Там полно теорий про стоимость операций при разных способах хранения данных.
V>Вопрос на мильон $$, почему в рамках теории реляционных СУБД постоянно упоминается "несогласованное обновление", "ошибки целостности" и т.д. Ведь, с т.з. РА, например, такое невозможно?
Так в рамках практики, или в рамках теории? Вы уже определитесь.
V>ИМХО, ты классически ставишь телегу впереди лошади. Не РА является определяющим в отношениях теории и практики, а наоборот, когда данные УДАЛОСЬ привести в рамки требований РА, можно начинать применять сей аппарат. Это общий алгоритм в любом случае, когда ты хочешь использовать какой-либо матаппарат для своих нужд, не только для реляционных СУБД.
V>Повторюсь, если ключ был суррогатный, то "потенциальность" повторов очень под вопросом. А если не суррогатный, то я хочу увидеть задачу целиком и убедиться что да, повторы были оправданы. Мне нужен верифицируемый пример.
Я привёл вам пример три поста назад.
V>Господя. MS SQL способен выдавать данные быстрее, даже с учетом всех join и т.д. на современных серваках, чем дотнетный парсер на стороне клиента способен парсить приходящие данные, а потом еще делать ORM. О чем ты тут пытаешься фантазировать?..
Я пытаюсь объяснить недалёкому собеседнику, как работают реальные сервера.
V> Что и как ты меряешь, не поделишься техникой? Тем паче, что возврат более нескольких сотен (грубо) записей из MS SQL всегда просит к себе некоторого внимания, на предмет "а зачем так?".
При чём тут "возврат"? Вот я пишу операцию, возвращающую 1 число:
select count(*) from sysobjects, sysobjects, sysobjects, sysobjects
Вы думаете, скорость "возврата результата" будет как-то быстрее, чем дотнетный парсер на стороне клиента? Ну удачи.
V>Уже показывал декомпозицию с вводом системного суррогатного ключа, некоего адреса строки, обеспечивающего O(1) для доступа.
И как это относится к кластерным индексам?
V>Хотя, указанная факторизация лежит вне РА (хоть и совсем рядом), все операции над декомпозицией можно проводить, используя аппарат РА. Исключения составляют неуникальные индексы, которые являются спорной техникой сами по себе, если не являются кластерными при этом. Это я к тому, что делать кластерным внешний ключ бывает намного полезней, чем основной, в плане эффективности. Именно потому, что по основному ключу достается единичная запись, а по внешнему мн-во, поэтому порядок хранения записей начинает играть роль.
Всё зависит не от внешности ключа, а от паттернов доступа. Если я использую запросы типа where primary_key between @low and @high, то несмотря на его уникальность я получу range. Ситуация часто возникает при, скажем, постраничном доступе к данным.
И неуникальные индексы, конечно же, никакой спорной техникой не являются. Это вы просто в предмете не разобрались как следует.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, samius, Вы писали:
DG>>это надо тебя спросить. S>Я такого не утвреждал. Sinclair?
Я утверждал. Если пройти по логическому пути по убиранию мутабельности из "объектов" Point, то они перестанут быть объектами в смысле ООП. Понятие "один и тот же" для них отпадёт вместе с identity, которая станет не нужна. Вместо этого будет достаточно эквивалентности, определённой как совпадение состояний.
Простой пример на пальцах:
p1 = new Point(1.1);
p2 = p1.Inverse(); // нет, p2 - это никоим образом не "та же самая" точка, что и p1. Рассуждения про "версионную identity" - это антинаучный бред.
p3 = p2.Inverse(); // нет, p3 - это не та же самая точка, что и p2.
Зато p1 эквивалентна p3 в том смысле, что их можно везде использовать взаимозаменяемо, и на все "сообщения" они будут реагировать строго одинаковым образом.
Этот код легко организовать на дотнете, использовав struct Point. Он не будет вести себя как объект, и попытки обмануть природу при помощи боксинга и referenceEquals не покажут ничего интересного.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>результативность не является достаточным критерием для обоснования хорошести решений. как минимум еще выделяют эффективность, экономичность, экологичность. на следующий уровнях еще больше плоскостей выделяется.
Вообще-то в 4Е четвёртая Е — это "этичность", а не экологичность. Но забавно, что вы переносите концепции из теории менеджмента в программирование.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
V>Кстати, подходящий пример. Если размер таблицы относительно мал, то кластерный индекс по passportNumber вполне покатит, но если же во много раз больше размеров ОП, то кластерный будет существенно сливать некластерному по тому же полю при выборе одиночных значений. V>И вообще, сорри конечно, но у меня закралось предположение, что реальную производительность кластерных индексов vs некластерных ты не измерил ни разу в жизни. Более того, сама мысль, что физически размер строки таблицы "не при чем" когда речь идет об эффективности кластерного индекса (эффективности поиска по нему, надо полагать) порождает еще кое-какие подозрения, но я их оставлю на следующую итерацию. Возможно, что ты просто подзабыл кое-что...
Да, кстати — на основе результатов забега "кластерные против некластерных" на "широкой" таблице, я начинаю испытывать желание проверить ваш рассказ про "мьютекс на создание делегатов". Может быть, он — тоже горячечный бред?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Вообще-то в 4Е четвёртая Е — это "этичность", а не экологичность.
в разных трактовках по разному.
при этом экологичность более определенное и более широкое понятие, чем этичность, т.к. этичность сильно зависит от текущей культуры.
> Но забавно, что вы переносите концепции из теории менеджмента в программирование.
программирование — это управляемая деятельность, и соответственно для нее справедливы всё то, о чем говорит менеджмент.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
DG>>>это надо тебя спросить. S>>Я такого не утвреждал. Sinclair? S>Я утверждал. Если пройти по логическому пути по убиранию мутабельности из "объектов" Point, то они перестанут быть объектами в смысле ООП. Понятие "один и тот же" для них отпадёт вместе с identity, которая станет не нужна. Вместо этого будет достаточно эквивалентности, определённой как совпадение состояний.
достаточно ли только такой эквивалентности, чтобы сделать вывод корректно ли преобразование(при суперкомпиляции, рефакторинге и т.д.) из функции T F(T item) в метод class T{void F()}?
вопрос всё тот же:
почему функцию Inverse корректно преобразовывать в метод Inverse
Point Inverse(this Point point)
{
return new Point(x:-point.X, y:-point.Y);
}
class Point-штрих
{
public void Inverse()
{
X = -X;
Y = -Y;
}
}
а функцию FindNearest нет?
public Point FindNearest(Point point, IEnumerable<Point> etalonPoints)
{
return etalonPoints.MinElement(etalon => (point.X-etalon.X)*(point.X-etalon.X) + (point.Y-etalon.Y)*(point.Y-etalon.Y)) ?? Point.Zero;
}
class Point-штрих
{
public void FindNearest(IEnumerable<Point-штрих> etalonPoints)
{
var p = etalonPoints.MinElement(etalon => (point.X-etalon.X)*(point.X-etalon.X) + (point.Y-etalon.Y)*(point.Y-etalon.Y)) ?? Point.Zero;
X = -p.X;
Y = -p.Y;
}
}
так же есть и вопрос и про обратное преобразование:
если код содержащий mutable-объект автоматически преобразовывается в код с immutable-объектом, то как меняется функция проверки, что объект тот же самый?
Здравствуйте, DarkGray, Вы писали:
S>> Вся работа кода выражается в терминах преобразования и переноса данных без изменения identity.
DG>почему для функции InversePoints следующий переход верен (из immutable-объектов в mutable) DG>
DG>void InversePoints_Inplace(this Point[] points)
DG>{
DG> var _points = new S_Point[points.Length];
DG> for(int i = 0; i < points.Length; ++i)
DG> {
DG> _points[i].X = -points[i].X;
DG> _points[i].Y = -points[i].Y;
DG> }
DG> for(int i = 0; i < points.Length; ++i)
DG> {
DG> points[i].X = _points[i].X;
DG> points[i].Y = _points[i].Y;
DG> }
DG>}
DG>
DG>а для функции FindNearest переход не верен? в чем отличие? и как его можно формализовать?
Для функции InversePoints ты специфицировал ожидаемый результат. Что при повторении точек каждая из них должна быть инвертирована однажды. А для функции FindNearest ты результат не специфицировал.
Кстати, суперкомпилятор не сможет за тебя это сделать. Максимум на что можно рассчитывать — на код с результатом, эквивалентным некоторому заданному. Да, я не понимаю, что такое "// meta hint", потому скипаю.
DG>
DG>void FindNearest_Inplace(this Point[] points, IEnumerable<Point> etalonPoints)
DG>{
DG> var _points = new S_Point[points.Length];
DG> for(int i = 0; i < points.Length; ++i)
DG> {
DG> var p = FindNearest(point, etalonPoints);
DG> _points[i].X = p.X;
DG> _points[i].Y = p.Y;
DG> }
DG> for(int i = 0; i < points.Length; ++i)
DG> {
DG> points[i].X = _points[i].X;
DG> points[i].Y = _points[i].Y;
DG> }
DG>}
DG>
не определена переменная "point". если поправить на points[i], то вроде бы все соответствует тому, как я бы определил поведение FindNearest инплейс. Т.е. если даже points и etalonPoints содержат идентичные точки, то ничего дурного не случится, т.к. расчеты проведутся до того как координаты точек перепишутся результирующими значениями.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
DG>>>это надо тебя спросить. S>>Я такого не утвреждал. Sinclair? S>Я утверждал. Если пройти по логическому пути по убиранию мутабельности из "объектов" Point, то они перестанут быть объектами в смысле ООП.
По-моему не так давно вы согласились со мной что они все же не перестают быть объектами в смысле ООП.
S>Понятие "один и тот же" для них отпадёт вместе с identity, которая станет не нужна. Вместо этого будет достаточно эквивалентности, определённой как совпадение состояний.
identity для них не отпадает. Просто она становится по силе эквивалентной эквивалентности. Но это не значит что она отпала.
S>Простой пример на пальцах: S>
S>p1 = new Point(1.1);
S>p2 = p1.Inverse(); // нет, p2 - это никоим образом не "та же самая" точка, что и p1. Рассуждения про "версионную identity" - это антинаучный бред.
S>p3 = p2.Inverse(); // нет, p3 - это не та же самая точка, что и p2.
S>
и не та же, что и p1 (при ссылочном типе точек). S>Зато p1 эквивалентна p3 в том смысле, что их можно везде использовать взаимозаменяемо, и на все "сообщения" они будут реагировать строго одинаковым образом.
На все сообщения — да, но сравнение ссылок даст их отличить. Соответственно, вся логика, которая может быть построена на сравнении ссылок, будет чувствительна. S>Этот код легко организовать на дотнете, использовав struct Point. Он не будет вести себя как объект, и попытки обмануть природу при помощи боксинга и referenceEquals не покажут ничего интересного.
Со struct — да, будет не докопаться.
V>>Императивное программирование — технология программирования, характеризующаяся принципом последовательного изменения состояния вычислителя пошаговым образом.
S>Ну вот видите, как вы начинаете подтверждать то, что я вам рассказываю. В РА нет никакого последовательного изменения состояния вычислителя.
Хе, в С++ тоже нет никакого вычислителя явно. Речь шла об упорядоченности операций. Ты заявлял о том, что последовательность операций не принципиальна. Я отвечал, что для конкретной формулы РА — принципиальна. Ниже чуть подробнее.
V>>Мммм, это должно сойти за док-во, что для конкретной формулы РА порядок вычислений и прочее не важно, не так ли? S>Это должно сойти за доказательство того, что РА не навязывает порядок вычислений.
Для конкретной выбранной формулы — навязывает еще как. Ты не обратил внимание на характер "раскрытия скобок" по ссылке? Зачастую никакие скобки раскрыть невозможно, особенно когда применяются ф-ии, заданные по условию, например так:
y = f1(f2(f3(f4(x))))
Поэтому, если в некоей формуле-предикате идет ограничение по некоему условию, содержащему некие аттрибуты, то мы не можем произвести преобразование выражения с выносом этого аттрибута. Все показанные преобразования верны только для независимого ограничения по каждому из аттрибутов или когда исходные условия ограничения удается декомпозировать по независимым аттрибутам.
Например, по самой дорогостоящей операции и самому важному преобразованию, обрати внимание по особственной ссылке на "Selection and cross product":
In the above case we break up condition A into conditions B, C and D using the split rules about complex selection conditions, so that A = B C D and B only contains attributes from R, C contains attributes only from P and D contains the part of A that contains attributes from both R and P. Note, that B, C or D are possibly empty.
Т.е. если такое разбиение условия A невозможно, то это преобразование НЕПРИМЕНИМО.
Более того, если декомпозиция находится не в 6-й НФ, т.е. присутствует хоть какая-то избыточность, то у нас есть возможность получить несколько вариантов РА формул для конечного результата, которые НЕ БУДУТ приводимы одни к другим через операции по ссылке, т.к. используют разные отношения в кач-ве аргументов в рамках всей декомпозиции. Я бы назвал этот эффект главным св-вом избыточности. Заметь, на уровне РИ это непринципиально, в отличие от уровня РА, бо РИ игнорирует конкретный вид декомпозиции, важны только зависимости м/у атрибутами в рамках ВСЕЙ схемы данных, но на уровне РА никакие зависимости, кроме ключей, уже не присутствуют.
Итого, переход вот он: это вся схема, по которой проводится декомпозиция под управлением зависимостей (это все НФ), а затем по полученной декомпозиции можно составлять выражения РА для поиска решения, заданного в терминах РИ, причем эти решения будут в общем случае неприводимы один к другому даже через приведенные тобой формулы. Ну а в некоторых частных случаях вполне приводимы, дык ради бога.
Кароч, эти вещи были как бы сами собой разумеющиеся, бо находятся на поверхности, но мне уже порядком поднадоело их освещать для тебя, т.к. ты просто упираешься непонятно чего ради. Свое мнение о неоходимости хоть какой-то практики по этой теме я уже высказывал — сразу отпала бы необходимость толкать все эти банальности, т.к. ты бы столкнулся со всеми этими эффектами уже в первый день.
V>>В итоге, какой бы конкретный вид формулы ты не выбрал для программирования, для нее будет важен порядок вычисления промежуточных аргументов с т.з. их последующего применения именно в этом варианте твоей формулы, пусть даже после 100500 преобразований от предполагаемой исходной формулы. S>Вы передёргиваете. Да, то, что исполняется реальным query engine — на 100% императивная программа. Там есть вычислитель, есть его состояние. Но между исходной формулой РА и реальным вычислением — бездна. Точно так же я могу сказать, что начав с предиката в РИ я всё равно приду к тому или иному виду физического плана исполнения запроса. Это ничего не говорит о том, что РИ само по себе сколь-нибудь императивно.
РИ конечно не императивно, оно декларативно.
Но твоя т.н. "бездна" — это всего навсего переход от модели таблицы как единого целого к модели ее декомпозиции, учитывающей все индексы по данной таблице. Т.е. нет никакой бездны, это тривиальные преобразования — переход от рассмотрения всей схемы с учетом зависимостей к рассмотрению декомпозиции, проведенной с учетом зависимостей. Далее. Как выбор конкретной формулы управляется оценочным аппаратом сложности — уже обсуждали выше. Но по сути моих возражений: обрати еще раз пристальное внимание, что если взять РАЗНЫЕ исходные отношения в декомпозиции с избыточностью (т.е. если взять любой индекс, а коль он не первичный ключ, он непременно избыточен!!!), то у нас получаются РАЗНЫЕ формулы РА, НЕПРИВОДИМЫЕ один к другому на уровне РА, но приводимые один к другому на уровне ВСЕЙ декомпозиции, т.е. уже на уровне РИ, на уровне полной схемы с учетом зависимостей. Так вот, для случая, когда преобразования условий выборки таки возможна, то весь аппарат РА применим к декомпозиции индекс-таблица. По крайней мере полно обсуждений относительно того, что происходит когда поля в ограничениях запроса есть в выбранном для сканирования индексе, или когда их нет. Это тупое применение наработок РА.
В общем, я крайне настоятельно рекомендую прямо здесь остановиться и собрать в одно всё что я говорил раньше и сейчас, бо повторяться по этой теме будет уже просто стыдно. Было сказано всё, что только можно.
S>Пока я не вижу у вас ни позитивных результатов самостоятельного освоения раздела, ни готовности внимать коллегам.
Ох и упорство, достойное лучшего применения.
V>>Остальное идет как контекст. Так вот, для случая кластерного индекса на странице содержится вся строка таблицы, т.е. на каждой странице будет меньше значений ключа, поэтому с т.з. быстродействия именно кластерного индекса, чем 'уже (в байтах) таблица, т.е. чем больше записей на каждой странице, тем шустрее поиск по этому ключу. Меньше потребуется просмотреть страниц в случае какого-нить двоичного поиска. S>А, я понял, в чём ваше заблуждение. Вы не понимаете, чем leaf pages кластерного индекса отличаются от non-leaf pages, и поэтому путаете размер ключа кластерного индекса с размером всей таблицы. Для "двоичного поиска" (которым вы, судя по всему, называете операцию index seek) в кластерном индексе конечно же не нужно просматривать "больше" страниц. Точно также просматривается logN.
Log2(N) просматривается в любом случае, отличие в том самом К.
S>Вы бы сразу спросили, если в Books Online непонятно написано.
S>Исходники? Зачем вам могли понадобиться исходники?
Понять причины тормозов внешних ключей в MS SQL.
В сравнении с тем же приложением на MS Access тормозило все минимум двухкратно при выборках на той же железке. Когда понял, минимизировал их абсолютный физический размер, изменив в справочниках, где можно, ключи на int8 и int16.
S>Запустите в нём вот такой вот несложный скрипт:
Запущу на досуге, но другой. У тебя два индекса идут по одной таблице, а это не соответствует нашему спору.
V>>Сорри, но это уже вовсе безграмотно... Зачем мне distinct при выборе уникальных значений из базы в 3-й НФ? Этот distinct мы уже сократили в уме. S>Вы-то сократили, а SQL — нет, не сократил.
И? Результат-то удовлетворяет. Что первично, а что вторично?
V>>А если неуникальные, т.е. не включающие ключи, — то они как раз выбираются для групповых операций, в т.ч. чтобы по ним специально сделать потом distinct. S>Ключевое слово — потом.
"Потом" — это всё еще в рамках того же выражения.
V>>Поэтому вопрос таки в силе, показать пример реального магазина или склада какого-нить, где действительно нужно гнать на клиента последовательность повторяющихся данных без групповых операций над ними. S>Я ничего не говорил про "гнать на клиента". Читайте то, что вам пишут, а не то, что вы себе придумываете.
Ага, таки неканонические данные не особо доступны извне (обычно это действительно так в нормальных приложениях). Дык, о чем речь тогда? О тонкостях реализации самого сервера? Смешно.
V>>А конкретное что-то есть, кроме общих фраз? S>Конкретно — отсутствие дубликатов, двузначная логика.
V>>Да просто сколько SQL-ей видел, столько раз их заново надо учить, это фактически другие языки, область пересечения диалектов ничтожна, буквально по самым простеньким запросам. S>Прекратите позориться. Есть большое количество кросс-СУБД проектов. Область пересчения диалектов значительно шире, чем чистый SQL-92.
Ну, значит мало ты переносил SQL-кода м/у базами. Так и будешь теоретизировать. Более 90% SQL-кода приходится переписывать/исправлять, при переходе с одной СУБД на другую.
V>>>>Читал, давно и многократно. Давай конкретную фразу/абзац/не_важно_что, которые должны что-то такое доказать. V>>Итого, в терминах двоичной логики решение принимается так: WHERE <search condition> IS TRUE. Это и есть boolean test. Заметь, не сравнение <search condition> = TRUE, а именно тест IS TRUE. S>Это я и пытаюсь объяснить уже два поста. См. мой пример с юнионом двух селектов.
Ох и юлить...
V>>Это гребанный стыд уже... S>Да я вижу. Вы никому не говорите, где учились, а то опозорите свой ВУЗ.
V>>NOT — это ключевое слово языка, который разрабатывался чтобы быть максимально близким к человеческому английскому. S>NOT в данном контексте — это унарная функция, которая реализует в SQL операцию логического отрицания. Ваш К.О.
Не ф-ия а оператор.
V>>А что означает NOT в выражении: <expression> IS NOT NULL? S>Здесь это слово — часть оператора "IS NOT NULL". Конкретно этот оператор никогда не возвращает UNKNOWN. S>Никакого отношения к унарной логической функции NOT это не имеет. Чтобы два раза не вставать: Есть ещё NOT BETWEEN, NOT LIKE, и NOT IN.
Это обычный унарный оператор, как при любом другом предикате SQL, поэтому я им тебя не тыкал.
S>Кстати, об IS NOT NULL: выражение R IS NOT NULL не эквивалентно выражению NOT R IS NULL.
Накидал всего... Этого не достаточно для реабилитации, т.к. ты рассуждал о случаях, чтобы аргумент и р-т оператора NOT приводились к boolean, и на этом выводил "троичную логику, которая несовместима с РА", а это бред сивой кобылы. Boolean test выполняется над всем выражением. Мне потребовалось объяснять это 3 поста и заставить тебя сходить по собственной ссылке. Вот что бывает от неумения обобщать знания из разных областей, вот с чем я борюсь тут обычно. Ты не увидел полный аналог м/у операцией приведения типов и реляционным отношением.
V>>Таблица истинности для NOT расписана, эта операция определена в языке SQL над доменом {true, false, null}. S>Вообще-то {true, false, unknown}.
Oh my God
Можно я таки буду использовать то имя константы, которое использовано во всех виденных мною и тобою в реальной работе СУБД? Тем паче, что это совсем уж непринципиально и понятно как тебе, так и остальным. Спасибо.
V>>Но! boolean test производится не над каждой операцией в выражении, а над результатом всего выражения, каким бы составным оно не было. S>И каким образом это опровергает что-то из того, что я сказал?
Что нет никакого несоответствие с РА. Есть прописанное в стандарте правило, которое приводит результат выражения из домена { true, false, null} к домену { true, false }. Это преобразование в терминах РА обыгрывается вводом такого отношения и вперед! Твой пример становится очень даже решабельным в терминах РА, хотя ты трижды перед этим утверждал обратное.
V>>Тю, у MS SQL есть, а у MS Access уже нет. В общем, мне эта тема неинтересна, бо она по-факту малопоследовательна, глядя на мн-во реализаций SQL в различных СУБД, чтобы делать какие-то выводы. S>Вы сначала разберитесь в основах, а потом будете делать какие-то выводы.
Угу, а у вас негров линчуют.
V>>В общем, если в ограничения целостности не вбили какое-то правило, то это чаще всего по соображениям эффективности, чтобы сервер не строил ненужный индекс и не делал на каждый чих лишние проверки, а не потому что такого ограничения в предметной области нет. S>Ну вот видите — через три поста вы таки понимаете, о чём я говорю. Да, уникальность не вбили в SQL по соображениям эффективности.
Дык, и в реальную модель не всегда вбивают. Понимаешь, не имеет значения, на каком уровне мы обеспечим соответствие данных требованиям реляционной модели. Частично это делается декларативными ср-вами СУБД, частично явно пользовательским кодом внутри триггеров, частично — клиентским приложением (неважно, трехзвенка там с еще одним промежуточным серваком или клиент-сервер). Я уже 10-й раз говорю, что коль такое соответствие получено, то аппарат становится доступен.
Как пример на более низком уровне — ты же сам привел ссылку где прямо написано:
Rules about selection operators play the most important role in query optimization. Selection is an operator that very effectively decreases the number of rows in its operand, so if we manage to move the selections in an expression tree towards the leaves, the internal relations (yielded by subexpressions) will likely shrink.
Это именно то, что происходит при составлении реального алгоритма исполнения запросов. (Физического плана запроса в терминах MS SQL)
S>Ну вот видите, как здорово. А ещё на прошлой неделе вам и в голову бы не пришло, что предикат в РА и предикат в SQL вообще могут означать разные понятия.
Мде, опять юлим. Ню-ню...
Я ведь вижу, что ты всё давно понял, что тебе говорилось изначально... но характер — штука сложная...
V>>Давай так. Ты еще ничего не обяснил. НИЧЕГО. Технические объяснения должны быть верифицируемы, а твой основной аргумент выглядит так: "вы неверно это себе представляете", что невозможно верифицировать. S>Почему? Возможно. Я даю вам задачу, вы её решаете. Если понимаете правильно — ответ совпадает. Если неправильно — ответ не совпадает.
Твою задачу с where (id=1) ты решил неверно для случая РА. Мне потребовалось 3 поста, чтобы объяснить ошибку в рассуждениях. Просто я вначале подумал, что одного только намека на верное решение будет достаточно. Но посмотри, сколько в итоге было понаписано вокруг банальной операции приведения типов, и даже цитировался стандарт... по тобой же данной ссылке... это просто трындец.
V>>Тоже самое касательно ограничений. Я 10-й раз прошу (и знаю, почему) придумать пример, где действительно НАДО выходить за рамки реляционной теории в реальных БД. S>Я вам привёл пример выше по топику. Встречный вопрос: зачем создатели SQL так мучились, вводя поддержку мультисетов в язык, если нигде в реальных примерах не нужно выходить за рамки реляционной модели?
Затем, чтобы иметь возможность выходить за рамки реляционной модели, когда это действительно нужно.
Я ведь затем и просил примеры, чтобы показать это. Что все эти рассуждения годятся исключительно для осознанного выхода за рамки реляционной модели, что практически всегда скорее исключение, чем правило. Например, хранение иерархических/древовидных данных в СУБД. С одной стороны, они могут находиться в отношениях с другими данными, подчиняющимися реляционной модели, но могут не находиться в этих отношениях сами с собой при популярной наивной реализации, когда невозможно определить через запрос SQL, является ли некий один узел транзитивно родителем другого и с какой вложенностью. Для ответа на этот вопрос надо задавать именно такое отношение, которое хранит эти зависимости, и которое будет избыточным по отношению к наивной схеме, что не всегда удобно. ИМХО, идеальным решением было бы создание СУБД, которая поддерживает как реляционную модель, так и иерархическую, и работу этого хозяйства совместно, тогда вопрос не возникал бы.
V>>У меня такое случалось и я знаю когда я это делал — это когда БД исопльзовалась не как реляционнное хранилище.Именно это я собирался продемоснтрировать на абсолютно любом приведенном примере, иначе бы он был сведен к вполне помещающемся в рамки наработок реляционной теории. Обсуждать технические решения вообще интересно само по себе, в отличие от гаданий, насколько "монолитно" (С) что-то у кого-то в голове. Это к мозгоправу, а не сюда. S>Мы находимся в форуме, посвящённом мозгоправлению. А я в данный момент играю роль мозгоправа.
Играй себе.
V>>Приехали... договорились... Да какую бы я реализацию реляционной модели не взял, она будет отличаться от реляционной модели хотя бы потому, что реляционная модель никак не ограничивает свою реализацию. Не понимаешь? Изначально подробностями реализации пренебрегли. Есть, конечно, кое-какие практические наработки и исследования стоимостей операций при разных способах хранения данных, но это сугубо инженерные исследования в конкретных, с т.з. инженерии, условиях, никак не связанных, разумеется, с теорией. S>С какой именно теорией? Прочтите учебник по разработке СУБД. Там полно теорий про стоимость операций при разных способах хранения данных.
О, так уже ты согласился с тем, что на этот счет вполне можно использовать теория реляционных БД? Без всей этой твоей "бездны"?
V>>Вопрос на мильон $$, почему в рамках теории реляционных СУБД постоянно упоминается "несогласованное обновление", "ошибки целостности" и т.д. Ведь, с т.з. РА, например, такое невозможно? S>Так в рамках практики, или в рамках теории? Вы уже определитесь.
Теории. Просто раздел РА — это всего лишь раздел. А вся теория реляционных БД как раз и посвящена разработке эффективных и непротиворечивых решений.
V>>Повторюсь, если ключ был суррогатный, то "потенциальность" повторов очень под вопросом. А если не суррогатный, то я хочу увидеть задачу целиком и убедиться что да, повторы были оправданы. Мне нужен верифицируемый пример. S>Я привёл вам пример три поста назад.
Я не увидел постановки задачи для этого решения. Пока нечего верифицировать.
V>>Господя. MS SQL способен выдавать данные быстрее, даже с учетом всех join и т.д. на современных серваках, чем дотнетный парсер на стороне клиента способен парсить приходящие данные, а потом еще делать ORM. О чем ты тут пытаешься фантазировать?.. S>Я пытаюсь объяснить недалёкому собеседнику, как работают реальные сервера.
А я пытаюсь объяснить, откуда взялась реляционная теория, и почему реальные сервера таки выгоднее таки делать как можно ближе к ней.
V>> Что и как ты меряешь, не поделишься техникой? Тем паче, что возврат более нескольких сотен (грубо) записей из MS SQL всегда просит к себе некоторого внимания, на предмет "а зачем так?". S>При чём тут "возврат"? Вот я пишу операцию, возвращающую 1 число: S>
S>select count(*) from sysobjects, sysobjects, sysobjects, sysobjects
S>
S>Вы думаете, скорость "возврата результата" будет как-то быстрее, чем дотнетный парсер на стороне клиента? Ну удачи.
Можно поинтересоваться, что это была за рефлексия и что она должна была доказать? Этот пример чем-то противоречит РА? Разве кортежи в sysobjects неуникальны? И разве нельзя выполнить оптимизацию конкретно этого запроса по всем правилам РА?
V>>Уже показывал декомпозицию с вводом системного суррогатного ключа, некоего адреса строки, обеспечивающего O(1) для доступа. S>И как это относится к кластерным индексам?
Почему именно к кластерным? Речь о том, чтобы рассматривать индекс как декомпозицию. Как именно организован переход от индекса к строке за O(1) оставим на совести конкретной СУБД.
V>>Хотя, указанная факторизация лежит вне РА (хоть и совсем рядом), все операции над декомпозицией можно проводить, используя аппарат РА. Исключения составляют неуникальные индексы, которые являются спорной техникой сами по себе, если не являются кластерными при этом. Это я к тому, что делать кластерным внешний ключ бывает намного полезней, чем основной, в плане эффективности. Именно потому, что по основному ключу достается единичная запись, а по внешнему мн-во, поэтому порядок хранения записей начинает играть роль. S>Всё зависит не от внешности ключа, а от паттернов доступа. Если я использую запросы типа where primary_key between @low and @high, то несмотря на его уникальность я получу range. Ситуация часто возникает при, скажем, постраничном доступе к данным.
OMG, постраничный доступ по первичному ключу?
Нахрена вам вообще реляционная СУБД, не пояснишь?
S>И неуникальные индексы, конечно же, никакой спорной техникой не являются. Это вы просто в предмете не разобрались как следует.
Это ты не разбрался как следует. Практически всегда неуникальный ключ можно обыграть дополнительным отношением, явно отражающим сценарии/потребности прикладной области, и получить больше прибавки к эффективности в итоге, ведь неуникальный индекс тоже сугубо для эффективности вводится. В общем, избыточность ненаказуема в рамках РА, коль удается поддерживать целостность, уже повторял многократно и это тоже своего рода инструмент.
S>Во-первых — я считаю что Sinclair читал достаточно много, и по субъективным впечатлениям значительно больше меня, а главное, с большим толком. Во-вторых, я считаю что Sinclair достаточно глубоко понимает материал, раскладывает его по полочкам, очень четко выделяет абстракции и их уровни.
для хорошего специалиста особенно при групповой деятельности (а форум — это, в первую очередь, групповая деятельность) этого мало.
хороший специалист еще должен осознавать, что он оперирует исходя из своей карты мира, и эта карта отдаленно совпадает с реальностью, и еще более отдаленно совпадает с картами мира, которые используют другие люди.
и не ощущается, что Sinclair это осознает. у тебя оно менее выражено, но тоже достаточно заметно.
S>А для функции FindNearest ты результат не специфицировал.
FindNearest возвращает одну из эталонных точек, и точку Zero, если эталонных точек нет.
> Т.е. если даже points и etalonPoints содержат идентичные точки, то ничего дурного не случится
данный mutable-код нарушает спецификацию, что должна вернутся одна из эталонных точек
DG>>вопрос всё тот же: DG>>почему функцию Inverse корректно преобразовывать в метод Inverse S>В общем случае — нет, некорректно. Вы же сами привели пример, где эти реализации не ведут себя одинаково. В конкретном коде это может оказаться корректным. То есть, к примеру, если вы выполнили в первом и втором случае все оптимизации компилятора — инлайнинг, распространение констант, алгебраические преобразования — и получился одинаковый целевой код, то да, преобразование было корректным.
ответ не конструктивный, и соответственно бесполезный — потому что не фиксирует, каких условий достаточно для входа, чтобы сделать определенный вывод про выход.
S>Ну, если у вас есть готовый автоматический преобразователь, то напустите его на код, использующий "функцию проверки". Он вам и выдаст результат.
так вот этот преобразователь и выдает так, как я говорил выше...
Здравствуйте, vdimas, Вы писали: V>Хе, в С++ тоже нет никакого вычислителя явно.
1. В С++ есть изменяемые переменные. Ничего подобного в РА нет.
2. В С++ есть чётко определённый порядок выполнения операций при вычислении аргументов бинарных операторов. Ничего подобного в РА нет.
3. В С++ есть побочные эффекты от операций (проявляющиеся в изменении состояния "вычислителя", т.е. значений переменных), из-за которых нужен пункт 2. Ничего подобного в РА нет. V>Речь шла об упорядоченности операций. Ты заявлял о том, что последовательность операций не принципиальна.
Всё наоборот. Вы кричали, что я вообще никогда не могу менять порядок операций в заданной РА-формуле. Я вас тыкаю носом в раздел, где английским по белому написано, при каких условиях и какие операции можно местами менять.
V>Для конкретной выбранной формулы — навязывает еще как. Ты не обратил внимание на характер "раскрытия скобок" по ссылке? Зачастую никакие скобки раскрыть невозможно,
"Зачастую" != "всегда". Учите формальную логику — в жизни пригодится.
V>Log2(N) просматривается в любом случае, отличие в том самом К.
Откуда вы взяли 2 в основании логарифма? Чему у вас равно K? За счёт чего у вас K при кластерном индексе окажется больше, чем при некластерном?
V>Запущу на досуге, но другой. У тебя два индекса идут по одной таблице, а это не соответствует нашему спору.
Нет проблем. Вот вам вариант с двумя таблицами — тут я вообще выкинул всё лишнее. Даже специально для вас заполнил padding данными, чтобы не было искушения сказать, что я смухлевал. Ну, и чтобы было понятно, что происходит, вывел статистику по allocation units.
create database TestDB;
GO
use TestDB;
GO
CREATE TABLE [dbo].[Test1]
(
id int identity primary key clustered,
padding char(7950) not null default replicate('#', 7950)
)
CREATE TABLE [dbo].[Test2]
(
id int identity primary key nonclustered,
padding char(7950) not null default replicate('#', 7950)
)
GO
CREATE PROCEDURE [dbo].[Initialize]
@size int
AS
set nocount on;
delete from Test1;
delete from Test2;
declare @i int;
set @i = 0;
while @i< @size
begin
insert into Test1 default values;
insert into Test2 default values;
set @i = @i + 1;
if (@i / 100)*@i = @i
begin
commit tran
begin tran
end
end
RETURN 0
GO
set nocount on
begin tran
declare @pageCount int
set @pageCount = 10000 -- укажите здесь количество страниц, которые вы хотите поместить в эту таблицу exec Initialize @pageCount
SELECT left(o.name, 10) AS table_name, p.index_id, left(i.name, 25) AS index_name , left(au.type_desc, 25) AS allocation_type, au.data_pages
FROM sys.allocation_units AS au
JOIN sys.partitions AS p ON au.container_id = p.partition_id
JOIN sys.objects AS o ON p.object_id = o.object_id
JOIN sys.indexes AS i ON p.index_id = i.index_id AND i.object_id = p.object_id
WHERE o.name like N'Test%'
ORDER BY o.name, p.index_id;
set statistics io on
declare @testid int
select @testid = cast(round(RAND()*@pageCount, 0, 0) as int)
select len(padding) from Test1 where id = @testid;
select len(padding) from Test2 where id = @testid;
commit tran
use master
drop database TestDB
Как вы думаете, какая будет разница в "К перед Log2(N)"?
V>И? Результат-то удовлетворяет. Что первично, а что вторично?
Первично то, что у запросов SQL есть определённая семантика. И она определена так, как я говорю, а не так как вам хочется, и не так, как в РА.
V>"Потом" — это всё еще в рамках того же выражения.
Это неважно. Промежуточные результаты в SQL-запросе тоже имеют тип.
V>Ага, таки неканонические данные не особо доступны извне (обычно это действительно так в нормальных приложениях). Дык, о чем речь тогда? О тонкостях реализации самого сервера? Смешно.
Речь о тонкостях стандарта SQL, которые отличают его модель от реляционной модели.
V>Ну, значит мало ты переносил SQL-кода м/у базами. Так и будешь теоретизировать. Более 90% SQL-кода приходится переписывать/исправлять, при переходе с одной СУБД на другую.
Вот у вас столько апломба при суждениях о моём опыте. Вы облажаться с разбегу не боитесь?
По делу: вот ну нас нынешний проект. Работает одновременно на двух СУБД. Довольно-таки разных. Как вы думаете, сколько процентов SQL-кода в нём являются СУБД-специфичными?
Если ваше предположение выше верно, то должно быть 90%.
S>>Кстати, об IS NOT NULL: выражение R IS NOT NULL не эквивалентно выражению NOT R IS NULL.
V>Oh my God V>Можно я таки буду использовать то имя константы, которое использовано во всех виденных мною и тобою в реальной работе СУБД?
Ну, если вы мне покажете, где именно "в реальной работе СУБД" логическое выражение возвращает NULL, то на здоровье — используйте его.
V>Что нет никакого несоответствие с РА. Есть прописанное в стандарте правило, которое приводит результат выражения из домена { true, false, null} к домену { true, false }. Это преобразование в терминах РА обыгрывается вводом такого отношения и вперед! Твой пример становится очень даже решабельным в терминах РА, хотя ты трижды перед этим утверждал обратное.
Речь не о "решабельности", а о соответствии модели. Теперь у вас уже выходит, что в каждом select у нас неявно выполняется оператор объединения со специальным отношением SQLLogicToBoolean и последующим оператором выбора. А вовсе не так, что column list — это проекция, а where — это выбор, как кажется на первый взгляд.
V>Дык, и в реальную модель не всегда вбивают. Понимаешь, не имеет значения, на каком уровне мы обеспечим соответствие данных требованиям реляционной модели. Частично это делается декларативными ср-вами СУБД, частично явно пользовательским кодом внутри триггеров, частично — клиентским приложением (неважно, трехзвенка там с еще одним промежуточным серваком или клиент-сервер).
Это всё очень хорошо, но для того, чтобы начать "обпеспечивать соответствие данных требованиям реляционной модели" на клиенте, нужно сначала умственным мозгом понять, что "декларативных средств СУБД" может не хватить. А для этого надо понимать, что модель, предлагаемая стандартом SQL, и, тем более, реализованная в реальной СУБД, не совпадают с РА. V>Я уже 10-й раз говорю, что коль такое соответствие получено, то аппарат становится доступен.
Оттого, что вы что-то повторяете, оно не становится полезнее. Отвлечёмся на минуту от сложной для вас темы РА, возьмём простую арифметику.
Пусть у нас от функции сравнения двух "чего-нибудь" требуется возвращать отрицательное целое число, если первый аргумент меньше второго, 0, если аргументы равны, и положительное целое число, если второй аргумент больше первого (Ничего, если я в С# синтаксисе буду писать?):
public delegate int Comparer<T>(T x, t y);
Такой компаратор можно использовать, например, в обобщённом коде сортировки коллекций.
Теперь поставим задачу так: мы хотим написать обёртку, которая умеет "инвертировать" произвольный компаратор — чтобы легко сортировать "в обратном" порядке:
public class ComparerInvertor<T>
{
private Comparer<T> _innerComparer;
public ComparerInvertor(Comparer<T> innerComparer)
{
_innerComparer = innerComparer;
}
public Compare(T x, T y)
{
return ??? // как будет выглядеть код здесь?
}
}
Вопрос приведён прямо в коде.
V>Это именно то, что происходит при составлении реального алгоритма исполнения запросов.
Не совсем. Поверьте мне на слово — при составлении "реального алгоритма исполнения запросов" всё гораздо сложнее. В частности, selection operators запросто могут продвигаться и в обратную сторону — от листьев к корню.
V>Твою задачу с where (id=1) ты решил неверно для случая РА.
Приведите правильное решение.
V>Затем, чтобы иметь возможность выходить за рамки реляционной модели, когда это действительно нужно.
И когда же это действительно нужно? Почему мы не видим ни одной промышленной СУБД, которая не даёт выходить за рамки реляционной модели, если такие потребности "почти никогда" не встречаются?
V>Для ответа на этот вопрос надо задавать именно такое отношение, которое хранит эти зависимости, и которое будет избыточным по отношению к наивной схеме, что не всегда удобно. ИМХО, идеальным решением было бы создание СУБД, которая поддерживает как реляционную модель, так и иерархическую, и работу этого хозяйства совместно, тогда вопрос не возникал бы.
Ну, вообще-то в рамках реальных СУБД решение уже давно есть. Как в диалектах (см. CONNECT BY), так и в стандарте (см. WITH). Но это ничего — это всего лишь небольшое расширение
V>О, так уже ты согласился с тем, что на этот счет вполне можно использовать теория реляционных БД? Без всей этой твоей "бездны"?
Те теории, которые я имею в виду, не совпадают с "реляционной моделью", описанной в классике. А какие теории вы имеете в виду — мне остаётся только гадать.
V>Теории. Просто раздел РА — это всего лишь раздел. А вся теория реляционных БД как раз и посвящена разработке эффективных и непротиворечивых решений.
А что такое "вся теория реляционных БД", стесняюсь спросить?
V>Я не увидел постановки задачи для этого решения. Пока нечего верифицировать.
V>А я пытаюсь объяснить, откуда взялась реляционная теория, и почему реальные сервера таки выгоднее таки делать как можно ближе к ней.
Что ж они так далеко-то от неё делаются, если ближе якобы выгоднее?
V>Можно поинтересоваться, что это была за рефлексия и что она должна была доказать?
Она доказывает, что вопросы производительности не связаны напрямую с тем, каков объём возвращаемых данных. И что вопросы производительности получения промежуточных результатов очень даже важны.
S>>Всё зависит не от внешности ключа, а от паттернов доступа. Если я использую запросы типа where primary_key between @low and @high, то несмотря на его уникальность я получу range. Ситуация часто возникает при, скажем, постраничном доступе к данным.
V>OMG, постраничный доступ по первичному ключу?
А что вас беспокоит? Вы хотите ещё какую-то глупость сказать, как в случае с кластерными индексами? V>Нахрена вам вообще реляционная СУБД, не пояснишь?
Для хранения и обработки данных.
V>Это ты не разбрался как следует. Практически всегда неуникальный ключ можно обыграть дополнительным отношением, явно отражающим сценарии/потребности прикладной области, и получить больше прибавки к эффективности в итоге, ведь неуникальный индекс тоже сугубо для эффективности вводится.
Серъёзно что ли? Мне нравятся кванторы типа "практически всегда". Это вы себе лазейку оставляете для того, чтобы когда я вас носом ткну в реалистичный пример применения неуникального индекса, вы начали юлить типа "ой, ну это же так редко нужно"? Давайте вы вместо "практически всегда" напишете, когда именно "обыгрывание ключа дополнительным отношением" будет приводить к росту эффективности по сравнению с банальным create index. А когда, соответственно, наоборот.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>Эта рекомендация — полный бред. Размер данных таблицы не играет никакой роли.
DG>у вас не зафиксированы до конца термины, чтобы можно было делать такое сильное утверждение. DG>как минимум не зафиксировано: "о каких запросах вообще идет речь"?
В своих рекомендациях я указал, о каких запросах идёт речь.
Рекомендация vdimas-а бредовая, даже если попытаться её уточнить путём ограничения набора запросов, для которых она будто бы полезна.
DG>также не зафиксировано как определена операция сравнения для множеств через операцию сравнения для элементов.
Какие множества вы предлагаете сравнивать?
DG>зы DG>например, если запрос можно выполнить на основе лишь некластерного индекса(в частности, например, запрос существования записи) без последующего обращения к кластерному индексу, то поиск по некластерному индексу будет быстрее, и эффект будет тем сильнее проявляться, чем шире таблица.
О, ещё один великий практик SQL подтянулся. Давайте, глумитесь над бедным теоретиком.
И насколько конкретно поиск по некластерному индексу будет быстрее? Какова зависимость от ширины таблицы?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>ответ не конструктивный, и соответственно бесполезный — потому что не фиксирует, каких условий достаточно для входа, чтобы сделать определенный вывод про выход.
Какой вопрос, такой и ответ. Вы задаёте вопрос в стиле "почему бог создал адама из глины, а еву — из ребра". Что я могу вам ответить, кроме совета почитать что-нибудь о происхождении видов?
S>>Ну, если у вас есть готовый автоматический преобразователь, то напустите его на код, использующий "функцию проверки". Он вам и выдаст результат. DG>так вот этот преобразователь и выдает так, как я говорил выше...
Что? Ваш преобразователь как-то ухитряется вычислять невычислимую функцию "трассы"? Очень интересно. Вы мне исходничек преобразователя не скинете?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>данный mutable-код нарушает спецификацию, что должна вернутся одна из эталонных точек
Не вижу нарушения. Вы, наверное, хотели чтобы правильным ответом было
Здравствуйте, DarkGray, Вы писали:
S>>Во-первых — я считаю что Sinclair читал достаточно много, и по субъективным впечатлениям значительно больше меня, а главное, с большим толком. Во-вторых, я считаю что Sinclair достаточно глубоко понимает материал, раскладывает его по полочкам, очень четко выделяет абстракции и их уровни.
DG>для хорошего специалиста особенно при групповой деятельности (а форум — это, в первую очередь, групповая деятельность) этого мало. DG>хороший специалист еще должен осознавать, что он оперирует исходя из своей карты мира, и эта карта отдаленно совпадает с реальностью, и еще более отдаленно совпадает с картами мира, которые используют другие люди.
DG>и не ощущается, что Sinclair это осознает. у тебя оно менее выражено, но тоже достаточно заметно.
По-моему твоя реальность и карта мира намного дальше. И по твоему кунгфу ООП это заметно.
Здравствуйте, DarkGray, Вы писали:
S>>А для функции FindNearest ты результат не специфицировал.
DG>FindNearest возвращает одну из эталонных точек, и точку Zero, если эталонных точек нет.
Я о той, к которой якобы должен был стремиться суперкомпилятор, наваяв void FindNearest_Inplace(this Point[] points, IEnumerable<Point> etalonPoints).
Вот она совершенно не специфицирована.
>> Т.е. если даже points и etalonPoints содержат идентичные точки, то ничего дурного не случится
DG>данный mutable-код нарушает спецификацию, что должна вернутся одна из эталонных точек
Эту спецификацию я не видел и всерьез полагал что тебя устроит совпадение координат а не идентичность эталонной точки.
DG>>также не зафиксировано как определена операция сравнения для множеств через операцию сравнения для элементов. S>Какие множества вы предлагаете сравнивать?
множества времен выполнения запросов для кластерного и некластерного индекса.
или ты что-то другое имел ввиду когда заявлял "Размер данных таблицы не играет никакой роли"?
DG>>зы DG>>например, если запрос можно выполнить на основе лишь некластерного индекса(в частности, например, запрос существования записи) без последующего обращения к кластерному индексу, то поиск по некластерному индексу будет быстрее, и эффект будет тем сильнее проявляться, чем шире таблица. S>О, ещё один великий практик SQL подтянулся. Давайте, глумитесь над бедным теоретиком. S>И насколько конкретно поиск по некластерному индексу будет быстрее? Какова зависимость от ширины таблицы?
в первом приближении: пропорционально отношению размера записи некластерного индекса к размеру записи в кластерном индексе.
изменение скорости выполнения обусловлено тем, что при запросе одной записи за то же время читается сразу группа записей, при этом размер группы фиксирован в байтах, а не в кол-ве записей, соответственно, чем меньше размер записи, тем больше их читается за один запрос, и соответственно тем выше вероятность, что следующая проверяемая запись будет уже в кэше, и что не надо будет ждать пока головка винта доедет до нужного места.
S>Я о той, к которой якобы должен был стремиться суперкомпилятор, наваяв void FindNearest_Inplace(this Point[] points, IEnumerable<Point> etalonPoints). S>Вот она совершенно не специфицирована.
функция FindNearest сдвигает каждую точку к ближайшей эталонной
ps
в итоге есть два варианта:
1. функция Point FindNearest(Point p, IEnumerable<Point> etalonPoints) возвращает ближайшую эталонную точку
2. функция Point FindNearest(Point p, IEnumerable<Point> etalonPoints) сдвигает точку к ближайшей эталонной (тогда, конечно, лучше эту функцию по другому назвать)
первый вариант корректно преобразуется к Point Point.FindNearest(IEnumerable<Point> etalonPoints), а второй к void Point.FindNearest(IEnumerable<Point> etalonPoints) и изменению текущего экземпляра
и соответственно, вопрос — в каких терминах можно записать это отличие для функции Point FindNearest(Point p, IEnumerable<Point> etalonPoints), если утверждается, что понятие identity здесь не применимо?
DG>>и не ощущается, что Sinclair это осознает. у тебя оно менее выражено, но тоже достаточно заметно. S>По-моему твоя реальность и карта мира намного дальше. И по твоему кунгфу ООП это заметно.
вот только в этом треде:
в основном только я выдаю какие-то реальные рабочие куски кода,
и это я выдал без запуска профайлера достаточно подробный анализ примера Sinclair-а содранного у липпера,
и это мой алгоритм выдал вариант InversePoints более оптимизированный, чем твой,
это я тебе показал два способа получить бинарное представление value-типов в .net, когда ты не смог найти ни одного
и т.д.
а ты (а уж тем более Sinclair) максимум, что делаете — это говорите бла-бла-бла, что мое кунфу плохое, потому что что-то там не совпадает с определениями, которые никто из вас даже не то что сам сформулировать не смог, а даже не смог тупо содрать из нужного места в интернете.
а наши кунфу, вы говорите, самое убойное, мы его подсмотрели у крутых авторитетов, мы, конечно, в нем ничего не понимаем — что откуда следует, но оно реально крутое, чувак.
соответственно, у тебя какая-то очень странная линейка, который ты измеряешь насколько близки твоя и моя карта мира к реальности.
Здравствуйте, DarkGray, Вы писали:
S>>Я о той, к которой якобы должен был стремиться суперкомпилятор, наваяв void FindNearest_Inplace(this Point[] points, IEnumerable<Point> etalonPoints). S>>Вот она совершенно не специфицирована.
DG>функция FindNearest сдвигает каждую точку к ближайшей эталонной
DG>ps DG>в итоге есть два варианта: DG>1. функция Point FindNearest(Point p, IEnumerable<Point> etalonPoints) возвращает ближайшую эталонную точку DG>2. функция Point FindNearest(Point p, IEnumerable<Point> etalonPoints) сдвигает точку к ближайшей эталонной (тогда, конечно, лучше эту функцию по другому назвать)
DG>первый вариант корректно преобразуется к Point Point.FindNearest(IEnumerable<Point> etalonPoints), а второй к void Point.FindNearest(IEnumerable<Point> etalonPoints) и изменению текущего экземпляра
DG>и соответственно, вопрос — в каких терминах можно записать это отличие для функции Point FindNearest(Point p, IEnumerable<Point> etalonPoints), если утверждается, что понятие identity здесь не применимо?
Я тебя спрашивал о другой функции, ведь твой предыдущий вопрос был о ней.
Совершенно непонятно, почему утверждается что понятие identity не применимо?
Здравствуйте, DarkGray, Вы писали:
DG>множества времен выполнения запросов для кластерного и некластерного индекса. DG>или ты что-то другое имел ввиду когда заявлял "Размер данных таблицы не играет никакой роли"?
Время тут ни при чём. Время выполнения запроса предсказать очень тяжело, т.к. оно зависит от огромного количества посторонних факторов.
В СУБД обычно считают логические чтения — количество страниц, которые нужно прочесть в процессе выполнения запроса. Берутся они из кэша или диска — зависит много от чего.
Так вот, если мы зафиксируем те ограничения, которые предложил коллега vdimas — поиск одного значения по ключу — то стоимость запроса для конкретных фиксированных данных в таблице не будет зависеть от параметра. Поэтому для кластерного индекса будем иметь KI чтений, а для некластерного — NI чтений.
Так вот, истинность KI>NI не зависит от размера одной записи S. И от количества записей N она тоже не зависит.
Именно это я и имел в виду, когда говорил, что "размер данных таблицы не играет никакой роли".
Она зависит только от того, входит ли запрашиваемое поле F в состав ключа некластерного индекса, или нет.
DG>>>зы DG>в первом приближении: пропорционально отношению размера записи некластерного индекса к размеру записи в кластерном индексе.
Давайте уточним, что вы назыв DG>изменение скорости выполнения обусловлено тем, что при запросе одной записи за то же время читается сразу группа записей, при этом размер группы фиксирован в байтах, а не в кол-ве записей, соответственно, чем меньше размер записи, тем больше их читается за один запрос, и соответственно тем выше вероятность, что следующая проверяемая запись будет уже в кэше, и что не надо будет ждать пока головка винта доедет до нужного места.
Понятно. То есть вы тоже не знаете, как устроены индексы в реальных СУБД. Вам слово B-tree что-нибудь говорит?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>>>и не ощущается, что Sinclair это осознает. у тебя оно менее выражено, но тоже достаточно заметно. S>>По-моему твоя реальность и карта мира намного дальше. И по твоему кунгфу ООП это заметно.
DG>вот только в этом треде: DG>в основном только я выдаю какие-то реальные рабочие куски кода,
Как я понимаю, в основном ты пытаешься доказать что без твоих трасс жить нельзя, но ни один кусок кода не оказался убедительным. Реальными и рабочими я бы их тоже постеснялся назвать, т.к. там участвует некий суперкомпилятор, чье существование под большим сомнением.
DG>и это я выдал без запуска профайлера достаточно подробный анализ примера Sinclair-а содранного у липпера,
Я читал блог Липперта и ковыряться в том коде мне было совершенно не интересно. Извини. DG>и это мой алгоритм выдал вариант InversePoints более оптимизированный, чем твой,
Разве было какое-то соревнование в оптимизаторстве? Я не знал. Ты мне пытался доказать что-то по трассам, разве нет?
DG>это я тебе показал два способа получить бинарное представление value-типов в .net, когда ты не смог найти ни одного DG>и т.д.
Даже не понимаю, о чем ты говоришь.
DG>а ты (а уж тем более Sinclair) максимум, что делаете — это говорите бла-бла-бла, что мое кунфу плохое, потому что что-то там не совпадает с определениями, которые никто из вас даже не то что сам сформулировать не смог, а даже не смог тупо содрать из нужного места в интернете.
Так ведь не совпадает. Сдесь важно это, а не то, кто смог содрать. DG>а наши кунфу, вы говорите, самое убойное, мы его подсмотрели у крутых авторитетов, мы, конечно, в нем ничего не понимаем — что откуда следует, но оно реально крутое, чувак.
Мы тебе только показываем что твое кунгфу не имеет ничего общего с кунгфу авторитетов.
DG>соответственно, у тебя какая-то очень странная линейка, который ты измеряешь насколько близки твоя и моя карта мира к реальности.
Странность — это отклонение от нормы. А что говоря о норме — так это твои теории далеки от нормального понимания ООП. Найди как минимум 2 человека, которые бы поддерживали твои взгляды на ООП, тогда поговорим о странностях еще раз.
V>>Хе, в С++ тоже нет никакого вычислителя явно. S>1. В С++ есть изменяемые переменные. Ничего подобного в РА нет. S>2. В С++ есть чётко определённый порядок выполнения операций при вычислении аргументов бинарных операторов. Ничего подобного в РА нет. S>3. В С++ есть побочные эффекты от операций (проявляющиеся в изменении состояния "вычислителя", т.е. значений переменных), из-за которых нужен пункт 2. Ничего подобного в РА нет.
Гы, ты опять пытаешься спор со мной увести на спор с самим собой... Было возражение насчет императивности? Я согласился, что подразумевал лишь то, что порядок вычисления важен, но коль тебе этого было мало, то давай уж добъем тему. Был дан конкретный пример инициализации переменных в С++, который остается корректным даже если в объявлении переменных поставить const (специально не поставил, было интересно спровоцировать и порассуждать о принципах иммутабельности, декларатиивной и фактической, по сути алгоритма, например). И был поставлен вопрос — это какое программирование? Ты же придрался, что не императивное, вот и расскажи, какое. Я вижу, что не функциональное ни разу, т.к. не присутствуют ф-ии как первокласссные объекты или операции над ними. А потом вернемся к РА, попробуем определить, под какое программирование оно подходит.
V>>Речь шла об упорядоченности операций. Ты заявлял о том, что последовательность операций не принципиальна. S>Всё наоборот. Вы кричали, что я вообще никогда не могу менять порядок операций в заданной РА-формуле.
Брехня, утверждалось, что в общем случае это невозможно. Опять же, крайне сложно спорить с "общей эрудицией"... то, что должно идти как само собой разумеющееся (а) не понимается, (б) требует итераций чтобы осознать, что не поняли (с) требует пояснять в итоге всё до молекул. Например, вот это преобразование:
Заметь, в этой формуле показано, коль анлитически из A удалось выделить B, C и D, то B и C могли быть применены к каждому из отношений предварительно, а D — нет. В общем, случае B и C могут быть пусты, там об этом тоже сказано. Т.е. их невозможно быдет выделить аналитически из А, например при обычном join по внешнему ключу. Надо просто читать внимательней. И самое главное, повторюсь — это не есть изменения порядка операций, даже если было что выделять, это выполнение ДРУГИХ операций после преобразования.
S>Я вас тыкаю носом в раздел, где английским по белому написано, при каких условиях и какие операции можно местами менять.
Что совсем не соответствует твоему утверждению, что порядок вычислений не важен. В РА выражение f(g(x)) не эквивалентно в общем случае g(f(x)). Более того, когда такая эквивалентность наблюдается, то эту формулу сводят в одну h(x) = f(x) AND g(x) еще на этапе упрощения выражения. Дабы уменьшить общее кол-во операций, банально не сканировать одни и те же данные многократно. Кароч, много слов, достаточно было знать, что не все операции РА являются коммутативными. Поэтому, если некие действия менять местами, то будут получены разные промежуточные результаты, что может сделать формулу невалидной. Что значит невалидной? Например, у нас есть объединение двух мн-в, эта операция требует 2 или более операндов одного уровня, и эти операнды должны быть совместимыми отношениями. Легко сделать так, что "тупое" изменение порядка операций при вычислении одного из операндов рассматриваемой операции объединения породит несовместимое с другими операндами отношение. Например при простой перестановке операций переименования и проекций — мы получим не те проекции не из тех атрибутов (не из тех доменов т.е.).
Т.к. толстых намеков было недостаточно, вот пример на пальцах. (докатились)
Есть унарное отношение A{a}, хранящее целые числа, допустим от -100 до 100. Есть отношение A'{a1, a2}, которое хранит результат некоей формулы, напр. a2(a1) = (-a1). Есть следующая последовательность операций:
B = выборка из А с ограничением x>5
D = выборка из B с ограничением x<15
E = выборка A'.a2 из D x A' где D.a = A'.a1
Легко заметить, что из всех возможных перестановок правых частей допустима только перестановка первой и второй операции, т.е. одна из 5-ти возможных. И то, пример искусственный. Обычно ни одной нельзя произвести после упрощения исходных формул (здесь — объединение первой и второй операции в одну). Т.е. вот у нас в примере есть целые числа и мы даже знаем как правильно менять условия, чтобы сохранить семантику даже после изменения порядка. Но для случая РА предполагается, что мы не можем делать никаких предположений о св-вах операций внутри доменов, которыми оперируем.
Ты же сам дал ссылку, где приведены правила (довольно нетривиальные) преобразования формул РА, а так же даны условия допустимости таких преобразований. Преобразования порождают другую формулу, т.е. другой конечный алгоритм, т.е. будут другие действия при выполнении алгоритма запроса. Это же не есть твоё "порядок выполнения операций не важен". Он важен точно так же, так же как для классичесского функционального программирования, где вышестоящие ф-ии используют результаты нижестоящих. Порядок не важен только для вычисления независимых промежуточных переменных-аргументов одного уровня. Ну дык, слово "независимый" ключевое, т.е. тут и обсуждать нечего. По крайней мере везде, где я говорил, что будет получаться другой тип промежуточных отношений — явно не про этот случай. (это я заранее на предмет возможных твоих виляний в плане независимых частей формулы).
V>>Для конкретной выбранной формулы — навязывает еще как. Ты не обратил внимание на характер "раскрытия скобок" по ссылке? Зачастую никакие скобки раскрыть невозможно, S>"Зачастую" != "всегда". Учите формальную логику — в жизни пригодится.
Гы, это ты себя поправил? Утверждалось, что в общем случае изменять порядок операций невозможно. Еще это:
Важно только одно — аргументами последующих операций являются результаты предыдущих. Это позволяет утверждать, что порядок вычислений важен.
Более того, в РА формулах допустимо вводить переменные и описывать конечный реультат как последовательность вычисления этих переменных. Да, при переносе алгоритма с бумаги в программу, сии переменные будут иммутабельные, т.к. вычисляются лишь однажды. Ну или можно использовать одну мутабельную переменную-ячейку для всех совместимых отношений, куда по мере вычислений помещать результаты вычисления разных "бумажных" переменных.. Но это всё подробности реализации и прочей экономии памяти, т.е. да, вполне можно расписать на иммутабельных переменных, если захотеть. Так вот, если эти вычисления делать не на ООП- или ФП-итераторах, а в виде энергичных вычислений, так какое это будет программирование?
S>Нет проблем. Вот вам вариант с двумя таблицами — тут я вообще выкинул всё лишнее. Даже специально для вас заполнил padding данными, чтобы не было искушения сказать, что я смухлевал. Ну, и чтобы было понятно, что происходит, вывел статистику по allocation units.
Ок, на выходных проверю, бо тут надо на 3 порядка больше страниц для моей машины, чтобы делать выводы.
V>>Ага, таки неканонические данные не особо доступны извне (обычно это действительно так в нормальных приложениях). Дык, о чем речь тогда? О тонкостях реализации самого сервера? Смешно. S>Речь о тонкостях стандарта SQL, которые отличают его модель от реляционной модели.
Лихо ты скачешь. Если вернуться чуть вверх, то спор зашел изначально об индексах, bookmark lookup и прочих низкоуровневых операциях, для которых я утверждал, что аппарат РА к ним применим. И ты правильную ссылку дал, кстати, что этот аппарат таки применим аж бегом. прямо по ссылке и написано, что используется для оптимизации запросов. А я снабдил твою ссылку правильными комментариями относительно того, что если принять индексы за декомпозицию исходных данных (с избыточностью, разумеется), то формулы выборки по разным индексам будут неприводимы друг другу на уровне РА, хотя приводимы на уровне РИ.
V>>Ну, значит мало ты переносил SQL-кода м/у базами. Так и будешь теоретизировать. Более 90% SQL-кода приходится переписывать/исправлять, при переходе с одной СУБД на другую. S>Вот у вас столько апломба при суждениях о моём опыте. Вы облажаться с разбегу не боитесь?
Нет.
S>По делу: вот ну нас нынешний проект. Работает одновременно на двух СУБД. Довольно-таки разных. Как вы думаете, сколько процентов SQL-кода в нём являются СУБД-специфичными? S>Если ваше предположение выше верно, то должно быть 90%.
Это зависит от того, насколько вы решили себя ограничить в конструкциях языка. У нас были проекты одновременно под Oracle, MS SQL, Postgre, иногда MS Jet. Проблемы начинаются уже на банальных вложенных запросах с зависимостями м/у уровнями, с квотированием, с пребразованием типов, синтаксисом параметров, типов данных, доступа из триггеров к текущей строке и т.д. до бесконечности. А когда доходит до кода процедур на оракле в сравнении с TSQL, то там примерно 100% кода требуют хоть какой-то, но коррекции. В общем, если база используется как хранилище объектов, а не серверное приложение, то в том же BLT есть адаптеры под различные СУБД, обыгрывающие небольшие тонкости небольшого класса выражений. Тут разница невелика. Если же "интеллектуальная нагрузка" на СУБД высока, то оценка в ~90% кода, требующего хотя бы косметических коррекций — вполне.
V>>Oh my God V>>Можно я таки буду использовать то имя константы, которое использовано во всех виденных мною и тобою в реальной работе СУБД? S>Ну, если вы мне покажете, где именно "в реальной работе СУБД" логическое выражение возвращает NULL, то на здоровье — используйте его.
SELECT (TRUE AND (5 > NULL)) — покатит?
Только это это какой-то шаг в сторону непонятно для чего. Не к чему больше придраться что ле?
V>>Что нет никакого несоответствие с РА. Есть прописанное в стандарте правило, которое приводит результат выражения из домена { true, false, null} к домену { true, false }. Это преобразование в терминах РА обыгрывается вводом такого отношения и вперед! Твой пример становится очень даже решабельным в терминах РА, хотя ты трижды перед этим утверждал обратное. S>Речь не о "решабельности", а о соответствии модели. Теперь у вас уже выходит, что в каждом select у нас неявно выполняется оператор объединения со специальным отношением SQLLogicToBoolean и последующим оператором выбора. А вовсе не так, что column list — это проекция, а where — это выбор, как кажется на первый взгляд.
Тю, блин, какой конфуз. А как по-твоему выглядит в терминах РА вот это:
select * from X where X.x1 in (select y1 from Y)
?
Тоже самое замечание относительно ANY, EXISTS, IN, CASE и т.д.
Таков уж язык SQL — позволяет одно и то же сказать десятками способов. Прямо как человеческая речь... её и копировал, кстате.
S>Это всё очень хорошо, но для того, чтобы начать "обпеспечивать соответствие данных требованиям реляционной модели" на клиенте, нужно сначала умственным мозгом понять, что "декларативных средств СУБД" может не хватить. А для этого надо понимать, что модель, предлагаемая стандартом SQL, и, тем более, реализованная в реальной СУБД, не совпадают с РА.
Ну мне остается только повторяться... Ограничения РА — это есть реляционная модель. Реляционная модель накладывает ограничения на данные, а не на инструментарий. Ферштейн?
И у меня есть в СУБД всяческий инструментарий для обеспечения целостности данных. Даже если нехватает декларативных ср-в в условиях специально примененной избыточности декомпозиции — есть механизм триггеров и транзакций, т.е. целостность можно соблюдать как "изнутри" базы, так и "снаружи".
Да, ты можешь не поддерживать целостность твоих данных, и тогда данные не будут отвечать реляционной модели, и тогда формулы РА по разным отношениям в условиях избыточности в декомпозиции схемы не будут эквивалентны на уровне РИ. Вот с этим предложением я уже давно согласился и тут же отбросил этот сценарий, как неинтересный для обсуждения. Бо нафига тогда реляционная СУБД была взята для задачи?
V>>Я уже 10-й раз говорю, что коль такое соответствие получено, то аппарат становится доступен. S>Оттого, что вы что-то повторяете, оно не становится полезнее. Отвлечёмся на минуту от сложной для вас темы РА, возьмём простую арифметику.
С какой целью?
S>Пусть у нас от функции сравнения двух "чего-нибудь" требуется возвращать отрицательное целое число, если первый аргумент меньше второго, 0, если аргументы равны, и положительное целое число, если второй аргумент больше первого (Ничего, если я в С# синтаксисе буду писать?):
... S>Вопрос приведён прямо в коде.
Если речь о "простой арифметике", то бишь о числах, то можно два варианта: поменять местами x и y согласно условия задачи (сортировки в обратном порядке), либо воспользоваться св-вом коммутативности числовой алгебры и просто поменять знак результата исходного компаратора, коль будет известно, что результат сравнения чисел реализован через вычитание. Если характер сравниваемых величин неизвестен, то остается первый способ, согласно условию.
Опять же ХЗ зачем ты делаешь очередные ответвления от и так раздутых постов...
V>>Это именно то, что происходит при составлении реального алгоритма исполнения запросов. S>Не совсем. Поверьте мне на слово — при составлении "реального алгоритма исполнения запросов" всё гораздо сложнее. В частности, selection operators запросто могут продвигаться и в обратную сторону — от листьев к корню.
Обратная сторона — это от корня выражения к листьям, а от листьев к корню — это естественный порядок вычисления ф-ий при энергичных вычислениях. Но опять же, не зацикливайся на простом selection, у него самое простое правило и им пользуются для упрощения, дабы не ходить многократно по одним и тем же правилам. Интерес представляют преобразования формул при наличии соединений, проекции и переименования. Чаще всего передвигают ближе к листьям именно проекции (т.е. вносят в скобки, размножают операцию), дабы минимизировать промежуточные результаты, а все переименования обычно наоборот — выносят за скобки на самый верх, чтобы сделать лишь одно результирующее переименование. наибольшую пищу для ума представляют, конечно, различные виды соединений. Их действительно иногда меняют местами, но не "просто", а именно порождая другой алгоритм.
V>>Твою задачу с where (id=1) ты решил неверно для случая РА. S>Приведите правильное решение.
Вводится ф-ия сравнения f для домена ID {MIN_INT..MAX_INT, null} возвращающая результат в домене SQL_PREDICATE {true, false, null}. Дальше продолжать или уже понятно, с учетом сказанного в пред. посте?
V>>Затем, чтобы иметь возможность выходить за рамки реляционной модели, когда это действительно нужно. S>И когда же это действительно нужно? Почему мы не видим ни одной промышленной СУБД, которая не даёт выходить за рамки реляционной модели, если такие потребности "почти никогда" не встречаются?
Наверно потому, что современные СУБД — это "вещь в себе", с дорогостоящей связью с внешним миром, т.е. требуется предоставить максимум ср-в внутри СУБД, чтобы писать разносторонние приложения. Как мы еще не дошли до обсуждения временных таблиц и императивных алгоритмов на курсорах? Непорядок, непорядок...
В общем, для СУБД в виде библиотек, используемых прямо из процесса-приложения, такого требования нет, поэтому сии библиотеки давали/дают более-менее небольшой набор операций, в отличие от современных TSQL или PL/SQL, остальное делается на прикладном уровне, коль позволяется навигация по результату выборки.
V>>Для ответа на этот вопрос надо задавать именно такое отношение, которое хранит эти зависимости, и которое будет избыточным по отношению к наивной схеме, что не всегда удобно. ИМХО, идеальным решением было бы создание СУБД, которая поддерживает как реляционную модель, так и иерархическую, и работу этого хозяйства совместно, тогда вопрос не возникал бы. S>Ну, вообще-то в рамках реальных СУБД решение уже давно есть. Как в диалектах (см. CONNECT BY), так и в стандарте (см. WITH). Но это ничего — это всего лишь небольшое расширение
Далеко не всех, а лишь где задекларирована поддержка SQL-99. MySQL, MS Access, MS ESQL и т.д. не понимают. Да и не такое уж это и небольшое расширение. Стало возможным задавать запросы, непредставимые в терминах РИ.
V>>О, так уже ты согласился с тем, что на этот счет вполне можно использовать теория реляционных БД? Без всей этой твоей "бездны"? S>Те теории, которые я имею в виду, не совпадают с "реляционной моделью", описанной в классике. А какие теории вы имеете в виду — мне остаётся только гадать.
V>>Теории. Просто раздел РА — это всего лишь раздел. А вся теория реляционных БД как раз и посвящена разработке эффективных и непротиворечивых решений. S>А что такое "вся теория реляционных БД", стесняюсь спросить?
Ссылку на самый популярный учебник уже давал. Там собраны теоретические наработки по реляционным БД, ИМХО, этот учебник больше всех рахватан на цитаты, конспекты, методички и прочие учебные пособия ВУЗов. По крайней мере выдержки из него встречал крайне часто в перечисленном.
V>>Я не увидел постановки задачи для этого решения. Пока нечего верифицировать.
V>>А я пытаюсь объяснить, откуда взялась реляционная теория, и почему реальные сервера таки выгоднее таки делать как можно ближе к ней. S> Что ж они так далеко-то от неё делаются, если ближе якобы выгоднее?
Делаются конкретные приложения. Ты снова и снова путаешь св-ва инструментария и характера данных. Не нужна тебе целостность — да не поддерживай, какие проблемы?
Мне важно обратное, что СУБД предоставляет все ср-ва для построения реляционной модели данных.
V>>Можно поинтересоваться, что это была за рефлексия и что она должна была доказать? S>Она доказывает, что вопросы производительности не связаны напрямую с тем, каков объём возвращаемых данных. И что вопросы производительности получения промежуточных результатов очень даже важны.
Ну это да... чтобы производительность получения промежуточных результатов не волновала особо, для исторических есть отдельно стоящий OLAP, а оперативные не особо велики, по меркам современных машин. Даже в конце 90-х на тех смешных машинах работа СУБД банка после отделения оперативных от промежуточных не вызывала проблем, не то что, на современной технике. Сегодня, даже если брать торговый день крупнейших бирж (чем занимаемся), то это сущая фигня, бо независимые данные разносятся по независимым таблицам, базам, серверам, кластерам.
V>>Это ты не разбрался как следует. Практически всегда неуникальный ключ можно обыграть дополнительным отношением, явно отражающим сценарии/потребности прикладной области, и получить больше прибавки к эффективности в итоге, ведь неуникальный индекс тоже сугубо для эффективности вводится. S>Серъёзно что ли? Мне нравятся кванторы типа "практически всегда". Это вы себе лазейку оставляете для того, чтобы когда я вас носом ткну в реалистичный пример применения неуникального индекса, вы начали юлить типа "ой, ну это же так редко нужно"? Давайте вы вместо "практически всегда" напишете, когда именно "обыгрывание ключа дополнительным отношением" будет приводить к росту эффективности по сравнению с банальным create index. А когда, соответственно, наоборот.
Когда будет — уже привел, это для случая кластерного неуникального индекса. А когда не будет эффективно — это описано много где в и-нете, не будет тогда, когда в сценарии требуются другие поля записи, помимо входящих в ключ. Для неуникального ключа — это практически всегда, кроме сценариев типа EXISTS. Вот из-за редкости такого сценария я позволил себе некое усиление, никакой тебе лазейки. Если сценарий доступа по такому неуникальному ключу устоявшийся, требует еще полей основной записи, выгодней сделать отдельное отношение, избыточное, но хранящее необходимые поля исходного отношения (естественно, если требуется не вся запись исходной таблицы, бо нет смысла в дубликате). Насколько выгодней — уже второй вопрос. Речь шла о выборке, напомню, иначе бы об эффективности не было разговору, бо при обновлении любой лишний индекс только утяжеляет операцию. Для примера, сокращение физического размера строк таблиц движений примерно вдвое (из-за выбора более узких типов данных для внешних ключей) подняло производительность пересчета проводок примерно вчетверо. Это эффект от уменьшения физического размера обрабатываемых данных, об этом речь. Ну и твой псих относительно "лазеек" таки доставляет. В чем вообще цель нашего обсуждения тут?
Здравствуйте, vdimas, Вы писали:
V>Гы, это ты себя поправил? Утверждалось, что в общем случае изменять порядок операций невозможно. Еще это: V>
V>Важно только одно — аргументами последующих операций являются результаты предыдущих. Это позволяет утверждать, что порядок вычислений важен.
Порядок вычислений и порядок композиции не одно и то же. Композиция не коммутативна, но никто не говорит что функция справа должна быть вычислена раньше, чем функция слева оператора композиции.
Здравствуйте, vdimas, Вы писали:
V>Гы, ты опять пытаешься спор со мной увести на спор с самим собой... Было возражение насчет императивности? Я согласился, что подразумевал лишь то, что порядок вычисления важен, но коль тебе этого было мало, то давай уж добъем тему. Был дан конкретный пример инициализации переменных в С++, который остается корректным даже если в объявлении переменных поставить const (специально не поставил, было интересно спровоцировать и порассуждать о принципах иммутабельности, декларатиивной и фактической, по сути алгоритма, например). И был поставлен вопрос — это какое программирование? Ты же придрался, что не императивное, вот и расскажи, какое. Я вижу, что не функциональное ни разу, т.к. не присутствуют ф-ии как первокласссные объекты или операции над ними. А потом вернемся к РА, попробуем определить, под какое программирование оно подходит.
Оставьте функциональное программирование в покое. Речь идёт об императивном vs декларативном.
V>Брехня, утверждалось, что в общем случае это невозможно.
Цитирую:
S>Я имею право как угодно переупорядочивать операции, если семантика сохраняется.
Не можешь! Сколько еще об этом говорить?
Цитирую опять:
На уровне РА отношения эквивалентности есть только у тех операций, которые выразимы через другие...
Оба утверждения, мягко говоря, далеки от истины. Я ткнул носом в отношения эквивалентности, которые применимы к невыразимым через другие операциям (например, к операции выбора), и которые, собственно, и задают границы "сохранения семантики".
V>Заметь, в этой формуле показано, коль анлитически из A удалось выделить B, C и D, то B и C могли быть применены к каждому из отношений предварительно, а D — нет. В общем, случае B и C могут быть пусты, там об этом тоже сказано. Т.е. их невозможно быдет выделить аналитически из А, например при обычном join по внешнему ключу. Надо просто читать внимательней. И самое главное, повторюсь — это не есть изменения порядка операций, даже если было что выделять, это выполнение ДРУГИХ операций после преобразования.
Давайте начнём с простого. Вот, например, попробуйте доказать, что это — не изменение порядка операций:
V>Что совсем не соответствует твоему утверждению, что порядок вычислений не важен. В РА выражение f(g(x)) не эквивалентно в общем случае g(f(x)).
Вы, по-видимому, неправильно понимаете утверждение, которое пытаетесь оспорить. Вы утверждаете, что в РА "порядок операций" задан всегда.
А я утверждаю, что нет, не всегда. Есть масса ситуаций, когда порядок операций можно изменить. Именно потому, что нет понятия "состояние вычислителя", т.е. РА имеет декларативную природу.
V>Легко заметить, что из всех возможных перестановок правых частей допустима только перестановка первой и второй операции, т.е. одна из 5-ти возможных.
Ну вот видите — возможна же? Это ровно совпадает с моим утверждением "возможна перестановка там, где не меняется семантика".
V>Он важен точно так же, так же как для классичесского функционального программирования, где вышестоящие ф-ии используют результаты нижестоящих.
Совершенно верно. Но ведь это не делает "классическое функциональное программирование" императивным.
V>Ок, на выходных проверю, бо тут надо на 3 порядка больше страниц для моей машины, чтобы делать выводы.
Ну давайте хотя бы порядок разницы предскажем, ок?
V>Лихо ты скачешь. Если вернуться чуть вверх, то спор зашел изначально об индексах, bookmark lookup и прочих низкоуровневых операциях, для которых я утверждал, что аппарат РА к ним применим. И ты правильную ссылку дал, кстати, что этот аппарат таки применим аж бегом. прямо по ссылке и написано, что используется для оптимизации запросов.
Да нет же, не используется.
V>Нет.
Ну, давайте подождём результатов запроса.
V>Если же "интеллектуальная нагрузка" на СУБД высока, то оценка в ~90% кода, требующего хотя бы косметических коррекций — вполне.
Ну вот видите, уже начинаются "если", "то", вводятся понятия "косметических коррекций"...
S>>Ну, если вы мне покажете, где именно "в реальной работе СУБД" логическое выражение возвращает NULL, то на здоровье — используйте его.
V>SELECT (TRUE AND (5 > NULL)) — покатит?
Вот сразу и видно, у кого есть практика, а у кого её нету.
MS SQL: Incorrect syntax near the keyword 'AND'.
SQLite3: Error: no such column: TRUE
Так что нет, не покатит. Приходите в другой раз.
V>Тю, блин, какой конфуз. А как по-твоему выглядит в терминах РА вот это: V>select * from X where X.x1 in (select y1 from Y) V>?
А это зависит от того, как определена табличка X. А то может и вовсе никак не выглядеть.
V>>>Я уже 10-й раз говорю, что коль такое соответствие получено, то аппарат становится доступен. S>>Оттого, что вы что-то повторяете, оно не становится полезнее. Отвлечёмся на минуту от сложной для вас темы РА, возьмём простую арифметику.
V>С какой целью?
S>>Пусть у нас от функции сравнения двух "чего-нибудь" требуется возвращать отрицательное целое число, если первый аргумент меньше второго, 0, если аргументы равны, и положительное целое число, если второй аргумент больше первого (Ничего, если я в С# синтаксисе буду писать?): V>... S>>Вопрос приведён прямо в коде.
V>Если речь о "простой арифметике", то бишь о числах, то можно два варианта: поменять местами x и y согласно условия задачи (сортировки в обратном порядке), либо воспользоваться св-вом коммутативности числовой алгебры и просто поменять знак результата исходного компаратора, коль будет известно, что результат сравнения чисел реализован через вычитание. Если характер сравниваемых величин неизвестен, то остается первый способ, согласно условию.
Ок, пусть у нас результат сравнения чисел реализован через вычитание. Я правильно понял из выделенного, что вы считаете вот такую реализацию корректной для "обычных" int32?
public class ComparerInvertor<T>
{
private Comparer<T> _innerComparer;
public ComparerInvertor(Comparer<T> innerComparer)
{
_innerComparer = innerComparer;
}
public int Compare(T x, T y)
{
return -_innerComparer(x, y);
}
}
...
public int IntCompare(int x, int y)
{
return x-y;
}
V>Опять же ХЗ зачем ты делаешь очередные ответвления от и так раздутых постов...
Минуточку. Скоро всё станет ясно.
V>Обратная сторона — это от корня выражения к листьям, а от листьев к корню — это естественный порядок вычисления ф-ий при энергичных вычислениях.
Перечитайте текст, который вы мне процитировали. Речь не о порядке вычисления, а о перемещении операций по дереву запроса ещё до начала исполнения.
V>Вводится ф-ия сравнения f для домена ID {MIN_INT..MAX_INT, null} возвращающая результат в домене SQL_PREDICATE {true, false, null}. Дальше продолжать или уже понятно, с учетом сказанного в пред. посте?
Ок, я понял вашу идею. Она заслуживает рассмотрения, хотя, скажем, сам Кодд почему-то был другого мнения, и построил расширение своей РА вместо сведения к дополнительным Join+Selection.
V>Наверно потому, что современные СУБД — это "вещь в себе", с дорогостоящей связью с внешним миром, т.е. требуется предоставить максимум ср-в внутри СУБД, чтобы писать разносторонние приложения.
Удивительно, как это авторы SQL предусмотрели вот эту возможность писать "разносторонние приложения" сразу же из коробки — не дожидаясь, когда появятся разносторнние приложения и начнут требовать поддержки нереляционных данных. И всё ещё в 80х. Зато вот производительность серверов их никак не интересовала — во-времена то, когда 16 мегабайт памяти на машине были большой редкостью, а гигабайтные базы — нет. V>Как мы еще не дошли до обсуждения временных таблиц и императивных алгоритмов на курсорах? Непорядок, непорядок...
Вы не переживайте, если потребуется — дойдём. V>Далеко не всех, а лишь где задекларирована поддержка SQL-99. MySQL, MS Access, MS ESQL и т.д. не понимают. Да и не такое уж это и небольшое расширение. Стало возможным задавать запросы, непредставимые в терминах РИ.
MS Access, простите, это настольная СУБД. Для промышленного использования она никогда и не предназначалась. А в SQL Server (всех редакций, включая Express) — есть. В оракле — есть. DB2 — есть. PostgeSQL — есть. Чего ещё?
V>Ссылку на самый популярный учебник уже давал.
А, понятно. То есть для вас теория == "предмет". Я так и думал.
V>Делаются конкретные приложения. Ты снова и снова путаешь св-ва инструментария и характера данных. Не нужна тебе целостность — да не поддерживай, какие проблемы? V>Мне важно обратное, что СУБД предоставляет все ср-ва для построения реляционной модели данных.
Задам вам ваш любимый вопрос: что первично?
V>Ну это да... чтобы производительность получения промежуточных результатов не волновала особо, для исторических есть отдельно стоящий OLAP, а оперативные не особо велики, по меркам современных машин.
Ага. То есть в 1986 году авторы стандарта SQL заранее знали, что в 2011 будет отдельно стоящий OLAP, а оперативные данные будут не особо велики, по меркам современных машин. И с дьявольской предусмотрительностью сделали основой модели SQL мультимножества для того, чтобы сразу же колбасить на SQL-совместимых СУБД постреляционные приложения и дать в полный рост развернуться системам ORM. Моя гипотеза про соображения производительности просто смехотворна.
Потрясающий анализ причинно-следственных связей, коллега. Поздравляю. Я бы так не смог.
S>>Серъёзно что ли? Мне нравятся кванторы типа "практически всегда". Это вы себе лазейку оставляете для того, чтобы когда я вас носом ткну в реалистичный пример применения неуникального индекса, вы начали юлить типа "ой, ну это же так редко нужно"? Давайте вы вместо "практически всегда" напишете, когда именно "обыгрывание ключа дополнительным отношением" будет приводить к росту эффективности по сравнению с банальным create index. А когда, соответственно, наоборот.
V>Когда будет — уже привел, это для случая кластерного неуникального индекса.
То есть для "кластерного неуникального индекса" ваше "обыгрывание ключа дополнительным отношением" будет приводить к росту эффективности, я вас правильно понял?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>это я тебе показал два способа получить бинарное представление value-типов в .net, когда ты не смог найти ни одного DG>>и т.д. S>Даже не понимаю, о чем ты говоришь.
S> Пардон, с наскоку не получилось сравнить структуры побитово.
DG>>а ты (а уж тем более Sinclair) максимум, что делаете — это говорите бла-бла-бла, что мое кунфу плохое, потому что что-то там не совпадает с определениями, которые никто из вас даже не то что сам сформулировать не смог, а даже не смог тупо содрать из нужного места в интернете. S>Так ведь не совпадает. Сдесь важно это, а не то, кто смог содрать.
как только ты говоришь про совпадение с реальностью, для начала необходимо показать (или хотя бы задуматься) какое определение одного и того же лучше совпадает с реальностью.
DG>>а наши кунфу, вы говорите, самое убойное, мы его подсмотрели у крутых авторитетов, мы, конечно, в нем ничего не понимаем — что откуда следует, но оно реально крутое, чувак. S>Мы тебе только показываем что твое кунгфу не имеет ничего общего с кунгфу авторитетов.
религия никакого отношения к реальности не имеет, а аппелирование к авторитету (а не к реальности) — это религия
DG>>соответственно, у тебя какая-то очень странная линейка, который ты измеряешь насколько близки твоя и моя карта мира к реальности. S>Странность — это отклонение от нормы. А что говоря о норме — так это твои теории далеки от нормального понимания ООП. Найди как минимум 2 человека, которые бы поддерживали твои взгляды на ООП, тогда поговорим о странностях еще раз.
тоже не понятно, какое это всё отношение имеет к совпадению с реальностью.
S> Странность — это отклонение от нормы.
и опять ты берешь слабое определение, сформулированное к тому же через понятие "норма" с очень высокой долей неопределенности
и приведенное тобой определение намного хуже совпадает с реальностью, чем определение "странный — не соответствующий ожиданиям".
DG>>>это я тебе показал два способа получить бинарное представление value-типов в .net, когда ты не смог найти ни одного DG>>>и т.д. S>>Даже не понимаю, о чем ты говоришь.
DG>http://rsdn.ru/forum/philosophy/4535554.aspx?tree=tree
S>> Пардон, с наскоку не получилось сравнить структуры побитово.
Ты не въехал, что у меня не получилось. У меня не получилось сравнить побитово структуры в общем виде. Пример —
struct X { object v; }
А уж как сравнить побитово встроенные значимые типы я бы догадался без твоих подсказок.
DG>>>а ты (а уж тем более Sinclair) максимум, что делаете — это говорите бла-бла-бла, что мое кунфу плохое, потому что что-то там не совпадает с определениями, которые никто из вас даже не то что сам сформулировать не смог, а даже не смог тупо содрать из нужного места в интернете. S>>Так ведь не совпадает. Сдесь важно это, а не то, кто смог содрать.
DG>как только ты говоришь про совпадение с реальностью, для начала необходимо показать (или хотя бы задуматься) какое определение одного и того же лучше совпадает с реальностью.
Твои определения не работают в рамках определений ООП. Потому связи с реальностью нет как раз у них. Я тебе показывал это на примере идентичности различных строк.
DG>>>а наши кунфу, вы говорите, самое убойное, мы его подсмотрели у крутых авторитетов, мы, конечно, в нем ничего не понимаем — что откуда следует, но оно реально крутое, чувак. S>>Мы тебе только показываем что твое кунгфу не имеет ничего общего с кунгфу авторитетов.
DG>религия никакого отношения к реальности не имеет, а аппелирование к авторитету (а не к реальности) — это религия
Я аппелировал к определению идентичности.
DG>>>соответственно, у тебя какая-то очень странная линейка, который ты измеряешь насколько близки твоя и моя карта мира к реальности. S>>Странность — это отклонение от нормы. А что говоря о норме — так это твои теории далеки от нормального понимания ООП. Найди как минимум 2 человека, которые бы поддерживали твои взгляды на ООП, тогда поговорим о странностях еще раз.
DG>тоже не понятно, какое это всё отношение имеет к совпадению с реальностью.
Это имеет отношение к "странности" линейки.
S>> Странность — это отклонение от нормы.
DG>и опять ты берешь слабое определение, сформулированное к тому же через понятие "норма" с очень высокой долей неопределенности DG>и приведенное тобой определение намного хуже совпадает с реальностью, чем определение "странный — не соответствующий ожиданиям".
А ты формулируешь через понятие "ожидание", которое еще более неопределенно, чем "норма".
S>Какой вопрос, такой и ответ. Вы задаёте вопрос в стиле "почему бог создал адама из глины, а еву — из ребра". Что я могу вам ответить, кроме совета почитать что-нибудь о происхождении видов?
один из стандартных советов: отвечайте так, чтобы посторонний наблюдатель мог перепроверить чья позиция ближе к реальности, не смотря на то, что он не знает модели обоих (не знает ни что такое "креационизм", ни что такое "происхождение видов"), а имеет какую-то свою модель.
соответственно, с точки зрения постороннего наблюда ответ выше ни чем не отличается от обратного ответа вида:
Как происхождение видов объясняет что человек обладает тем или свойством? Да почитайте вы наконец библию, там же все написано.
S>Ты не въехал, что у меня не получилось. У меня не получилось сравнить побитово структуры в общем виде. S>А уж как сравнить побитово встроенные значимые типы я бы догадался без твоих подсказок.
т.е. ты не знаешь, как из побитового сравнения встроенных типов сконструировать функцию, которая сравнивает структуры?
также следует, что не знаешь как получить битовое представление структуры?
DG>>как только ты говоришь про совпадение с реальностью, для начала необходимо показать (или хотя бы задуматься) какое определение одного и того же лучше совпадает с реальностью. S>Твои определения не работают в рамках определений ООП. Потому связи с реальностью нет как раз у них. Я тебе показывал это на примере идентичности различных строк.
определений ООП много, тебе необходимо сначала показать какое из них ближе к реальности, и почему.
DG>>>>а наши кунфу, вы говорите, самое убойное, мы его подсмотрели у крутых авторитетов, мы, конечно, в нем ничего не понимаем — что откуда следует, но оно реально крутое, чувак. S>>>Мы тебе только показываем что твое кунгфу не имеет ничего общего с кунгфу авторитетов.
DG>>религия никакого отношения к реальности не имеет, а аппелирование к авторитету (а не к реальности) — это религия S>Я аппелировал к определению идентичности.
пока не показано, как это связано с реальностью, это религия.
DG>>и приведенное тобой определение намного хуже совпадает с реальностью, чем определение "странный — не соответствующий ожиданиям". S>А ты формулируешь через понятие "ожидание", которое еще более неопределенно, чем "норма".
норма — это "усредненние" ожиданий членов группы, и здесь еще добавляется неопределенность от того, что можно взять разный способ "усреднения", а так же можно по разному брать группу, и соответственно норма имеет более высокую неопределенность, чем ожидание
Здравствуйте, DarkGray, Вы писали:
DG>а то каждый дурак говорит, что он понимает как всё устроено, вот только применить свои знания хоть для какой-нибудь оценки могут уже единицы.
Отлично. Давайте возьмём ваше "первое приближение".
пропорционально отношению размера записи некластерного индекса к размеру записи в кластерном индексе
Зададимся параметрами:
1. Размер записи некластерного уникального индекса по not null полю у нас равен size(key)+size(PageID)+2 байта расходов на index row entry. Пусть ключ будет классическим 4хбайтным целым. PageID, как известно, занимает 6 байт. Итого — 12 байт.
2. Размер записи в кластерном индексе мы положим тем же, что и в примере, который я опубликовал. Это 7950байт на "большую" колонку+4 байта ключа. Итого 7954.
Итого, вы меня пытаетесь уверить, что некластерный индекс будет работать быстрее "в первом приближении" в 662.5 раз?
Давайте я скажу вам своё первое приближение, а вы своё второе.
Правильный ответ: в первом приближении потребуется ровно столько же чтений для кластерного и некластерного индексов. Потому, что их non-leaf pages устроены совершенно одинаково: в них хранятся такие же 12-байтные index row entries. Отличия — только в leaf pages. В некластерном индексе в leaf pages хранятся такие же index row entries, а в кластерном вместо них выступают сами страницы с данными.
У кластерного индекса количество leaf pages в нашем случае, конечно же, больше. Ажно в 662.5 раз.
Но поскольку мы говорим о B-tree, то количество чтений определяется не количеством страниц, а его логарифмом.
Причём логарифмом по очень-очень большому основанию. В данном случае это 8096/12 = 674.
Итого,
Понятное дело, что читаем мы всегда целое количество страниц. Так что для кластерного индекса нам нужно примерно на 1 чтение больше.
Это если мы обошлись полем из индекса — т.е. к примеру проверяем exists().
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>Так вот, истинность KI>NI не зависит от размера одной записи S. И от количества записей N она тоже не зависит.
DG>как только ты от словоблудия перейдешь к написанию формулы кол-ва логических чтений для B-tree для тех или иных запросов, то сразу увидешь, что зависит.
Волшебным образом в B-tree количество чтений определяется логарифмом количества занятых страниц, которое, в свою очередь, пропорционально N.
Логарифм — функция монотонная. Поэтому если при каком-то N у нас получилось так, что KI>=NI, то это соотношение сохранится и при любом другом N.
Поэтому прекратите паясничать и идите читать букварь.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>соответственно, с точки зрения постороннего наблюда ответ выше ни чем не отличается от обратного ответа вида
Встречный совет — изучите формальную логику.
В ней из ложного высказывания следует любое другое.
Поэтому независимо от наличия постороннего наблюдателя имеет смысл избегать вопросов типа
если <заведомо ложный предикат> то <некий другой предикат>; объясните почему?
Не нравится вам библия — давайте я так спрошу: "если кирпич — жидкость, то почему мы строим стены из бетона"?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>Ты не въехал, что у меня не получилось. У меня не получилось сравнить побитово структуры в общем виде. S>>А уж как сравнить побитово встроенные значимые типы я бы догадался без твоих подсказок.
DG>т.е. ты не знаешь, как из побитового сравнения встроенных типов сконструировать функцию, которая сравнивает структуры?
Сравнить структуры я смогу с помощью побитового сравнения значений встроенных типов, а так же с помощью сравнения ссылок. Но сравнить побитово структуры и сравнить побитово значения примитивных типов полей структуры — это не одно и то же. Результат может совпадать, а сам процесс — будет отличаться. DG>также следует, что не знаешь как получить битовое представление структуры?
Те методы, что ты демонстрировал я знаю. И еще маршаллинг. Но не для любых структур они подходят. Уверен, что легально или нет, я битовое представление любой структуры в дотнете получу. Но не собираюсь этим заниматься только что бы доказать тебе что-то.
S>>Твои определения не работают в рамках определений ООП. Потому связи с реальностью нет как раз у них. Я тебе показывал это на примере идентичности различных строк.
DG>определений ООП много, тебе необходимо сначала показать какое из них ближе к реальности, и почему.
Мне это не нужно.
DG>>>религия никакого отношения к реальности не имеет, а аппелирование к авторитету (а не к реальности) — это религия S>>Я аппелировал к определению идентичности.
DG>пока не показано, как это связано с реальностью, это религия.
Пусть для тебя это религия. Для меня идентичность связана с программами, которые я (и не только) пишу. А они реальны.
DG>>>и приведенное тобой определение намного хуже совпадает с реальностью, чем определение "странный — не соответствующий ожиданиям". S>>А ты формулируешь через понятие "ожидание", которое еще более неопределенно, чем "норма".
DG>норма — это "усредненние" ожиданий членов группы, и здесь еще добавляется неопределенность от того, что можно взять разный способ "усреднения", а так же можно по разному брать группу, и соответственно норма имеет более высокую неопределенность, чем ожидание
Ожидание члена группы — без указания конкретного индивидума еще более неопределено чем усреднение ожиданий членов группы, т.е. норма.
Здравствуйте, Sinclair, Вы писали:
V>>Гы, ты опять пытаешься спор со мной увести на спор с самим собой... Было возражение насчет императивности? Я согласился, что подразумевал лишь то, что порядок вычисления важен, но коль тебе этого было мало, то давай уж добъем тему. Был дан конкретный пример инициализации переменных в С++, который остается корректным даже если в объявлении переменных поставить const (специально не поставил, было интересно спровоцировать и порассуждать о принципах иммутабельности, декларатиивной и фактической, по сути алгоритма, например). И был поставлен вопрос — это какое программирование? Ты же придрался, что не императивное, вот и расскажи, какое. Я вижу, что не функциональное ни разу, т.к. не присутствуют ф-ии как первокласссные объекты или операции над ними. А потом вернемся к РА, попробуем определить, под какое программирование оно подходит. S>Оставьте функциональное программирование в покое. Речь идёт об императивном vs декларативном.
Ну тогда можно сразу завязывать с ничьей, т.к. математическая нотация изначально слабо относится к парадигмам программирования, если быть строгим, т.е. обсуждение ни о чем. А насчет декларативного уже говорил, коль вместо описания св-в результата задается способ его получения, то тут декларативностью не пахнет.
S>Цитирую опять: S>
S>На уровне РА отношения эквивалентности есть только у тех операций, которые выразимы через другие...
S>Оба утверждения, мягко говоря, далеки от истины. Я ткнул носом в отношения эквивалентности, которые применимы к невыразимым через другие операциям (например, к операции выбора), и которые, собственно, и задают границы "сохранения семантики".
Уже показал на примере Cross production selection, где аналитический вид ф-ии ограничения считается известным, поэтому всё преобразование свелось к декомпозиции самой ф-ии ограничения и применения разных ее частей на разных этапах. Так вот, РА не занимается исследованием декомпозиций аналитических ф-ий, поэтому, хоть и показаны преобразования формул РА, это происходит не на уровне РА, а над ним. Вот тебе дадут ф-ию ограничения как черный ящик f(x), и ты "изнутри" самого инструментария РА ничего для случая Cross production selection сделать не сможешь.
V>>Заметь, в этой формуле показано, коль анлитически из A удалось выделить B, C и D, то B и C могли быть применены к каждому из отношений предварительно, а D — нет. В общем, случае B и C могут быть пусты, там об этом тоже сказано. Т.е. их невозможно быдет выделить аналитически из А, например при обычном join по внешнему ключу. Надо просто читать внимательней. И самое главное, повторюсь — это не есть изменения порядка операций, даже если было что выделять, это выполнение ДРУГИХ операций после преобразования. S>Давайте начнём с простого. Вот, например, попробуйте доказать, что это — не изменение порядка операций: S>
Это как раз случай явной выразимости одних операций через другие, т.е. таких, где не требуется знание аналитического вида формул. К тому же, про этот случай сказал в предыдущем сообщении, и его физический смыл был раскрыт в следующих строчках по твоей же ссылке:
Операция AND в условиях выборки коммутативна, поэтому да. Даи это было лишнее для аргументации. Ведь часть операций РА, которые являются теоретико-множественными, коммутативны сами по себе, поэтому можно было просто привести вот так еще в самом начале:
A AND (B AND C) = (A AND B) AND C.
A OR (B OR C) = (A OR B) OR C.
Где A,B,C — совместимые отношения. Сразу бы и отделили коммутативные от некоммутативных, чтобы не обобщать огульно.
V>>Что совсем не соответствует твоему утверждению, что порядок вычислений не важен. В РА выражение f(g(x)) не эквивалентно в общем случае g(f(x)). S>Вы, по-видимому, неправильно понимаете утверждение, которое пытаетесь оспорить. Вы утверждаете, что в РА "порядок операций" задан всегда. S>А я утверждаю, что нет, не всегда. Есть масса ситуаций, когда порядок операций можно изменить. Именно потому, что нет понятия "состояние вычислителя", т.е. РА имеет декларативную природу.
Нет, не поэтому, а исключительно из-за коммутативности. Аналогично вычислениям над обычными числами даже в императивной программе, часть вычислений можно проводить в произвольном порядке, если речь идет о коммутативных равноприоритетных операцих. Каким тут боком ты постоянно приплетаешь декларативность — это полное ХЗ. По твоим рассуждениям, декларативным является любое решение любой математической задачи, например, решение квадратного уравнения. А я считаю, что декларативно условие задачи — само уравнение, а его способ решение через нахождение дискриминанта — это именно последовательность решения, где дискриминант надо найти прежде, чем мы сможем через него найти корни уравнения.
V>>Легко заметить, что из всех возможных перестановок правых частей допустима только перестановка первой и второй операции, т.е. одна из 5-ти возможных. S>Ну вот видите — возможна же? Это ровно совпадает с моим утверждением "возможна перестановка там, где не меняется семантика".
РА не занимается семантикой, это делается на уровне РИ и реляционной модели. Т.е., чтобы провести все те преобразования формул РА, помимо заведомо коммутативных преобразований (т.е. безусловным образом выразимых через друг друга), нам нужно иметь всю модель, со всем ее физическим смыслом и зависимостями (т.е. с семантикой). Это не уровень РА.
V>>Он важен точно так же, так же как для классичесского функционального программирования, где вышестоящие ф-ии используют результаты нижестоящих. S>Совершенно верно. Но ведь это не делает "классическое функциональное программирование" императивным.
Возможно, хотя может сделать его процедурным, если мы не используем первоклассные ф-ии, не?
А процедурный подход относится к императивному или нет? Мне таки интересно твое развернутое мнение. Таки машина Тьюринга описана как автомат с ленточной памятью. Я ведь не зря привел "иммутабельный" вид инициализации после твоего повторного акцента на "императивный", бо тема скользкая даже для философии. А особенно если учесть, что ФП запросто может являться инструментом императивного программирования (что мы наблюдаем в современных императивных языках), то вообще границы получаются условными... В отличие от декларативных vs явно заданных вычислений.
V>>Ок, на выходных проверю, бо тут надо на 3 порядка больше страниц для моей машины, чтобы делать выводы. S> Ну давайте хотя бы порядок разницы предскажем, ок?
Ну коль для кластерного индекса строится точно такое же дерево на уровне неличтовых страниц, то чем он отличается от некластерного, когда на странице будет всего одна запись?
Вообще, надо поднять тот проект, посмотреть, почему после отказа от кластерных индексов по primary_key резко возросло общее быстродействие... Возможно, что по коссвенным к обсуждаемому причинам, например доступности теперь кластерного для внешних ключей. Насчет порядка: если некая соединительная операция из 3-х (грубо) составляющий выполняется в 4 раза быстрее, что каждая в среднем стала выполняться быстрее в корень 3-й степени из 4.
V>>Лихо ты скачешь. Если вернуться чуть вверх, то спор зашел изначально об индексах, bookmark lookup и прочих низкоуровневых операциях, для которых я утверждал, что аппарат РА к ним применим. И ты правильную ссылку дал, кстати, что этот аппарат таки применим аж бегом. прямо по ссылке и написано, что используется для оптимизации запросов. S>Да нет же, не используется.
Врет ссылка?
V>>Если же "интеллектуальная нагрузка" на СУБД высока, то оценка в ~90% кода, требующего хотя бы косметических коррекций — вполне. S>Ну вот видите, уже начинаются "если", "то"...
Гы, это не мое "если", а твое, ты же настаиваешь на кросс-СУБД проектах. Это очередной спор сам с собой, бо наличие области пересечения диалектов не отрицалось, но ей была дана низкая оценка, коль взять сразу несколько популярных СУБД (больше 2-х, хотя бы). Ну разумеется, b]если[/b] ты используешь только часть от всего разнообразия синтаксиса SQL, то для тебя может случиться так, что 100% кода не будут требовать переделки. Это не есть достойный аргумент против. Коль речь шла о сравнении SQL, я дал грубую прикидку по диалектам целиком.
S>>>Ну, если вы мне покажете, где именно "в реальной работе СУБД" логическое выражение возвращает NULL, то на здоровье — используйте его.
V>>SELECT (TRUE AND (5 > NULL)) — покатит? S> Вот сразу и видно, у кого есть практика, а у кого её нету. S>MS SQL: Incorrect syntax near the keyword 'AND'. S>SQLite3: Error: no such column: TRUE S>Так что нет, не покатит. Приходите в другой раз.
Угу, повеселил. Попробовал в MS Access, Oracle, Postgre, MySQL, DB2, d-base, FoxPro?
Ах какая неожиданная демонстрация предмета спора по предыдущему абзацу. Это же классический упс, не правда ли?
Для удобства в MS Access после проверки этого выражения проверь вот это:
SELECT (TRUE AND (5 > NULL)) IS NULL
Увидишь кой-чего интересное, тоже в плане переносимости очередная не всегда переносимая фишка (автоматическое/неавтоматическое приведение чисел к булевскому значению и обратно).
V>>Тю, блин, какой конфуз. А как по-твоему выглядит в терминах РА вот это: V>>select * from X where X.x1 in (select y1 from Y) V>>? S>А это зависит от того, как определена табличка X. А то может и вовсе никак не выглядеть.
Определена как отношение, в котором присутствует атрибут x1 по тому же домену, что и атрибут y1 в отношении Y.
Это я про то, что порядок и вид выражений РА вовсе не обязан соответствовать "естественному" порядку исходного SQL. И еще про то, что SQL крайне избыточен, позволяя задавать одни и те же запросы очень многими способами. Так вот, из приведения всех вариантов запросов к одному (для данного случая) варианту в терминах РА следует, что вид операций РА слабо связан с видом выражения в SQL.
V>>Если речь о "простой арифметике", то бишь о числах, то можно два варианта: поменять местами x и y согласно условия задачи (сортировки в обратном порядке), либо воспользоваться св-вом коммутативности числовой алгебры и просто поменять знак результата исходного компаратора, коль будет известно, что результат сравнения чисел реализован через вычитание. Если характер сравниваемых величин неизвестен, то остается первый способ, согласно условию. S>Ок, пусть у нас результат сравнения чисел реализован через вычитание. Я правильно понял из выделенного, что вы считаете вот такую реализацию корректной для "обычных" int32?
До сегодняшнего дня да, коль (x-y)==-(y-x).
Но у тебя ошибка в коде, нет учета переполнения. Надо так:
public int IntCompare(int x, int y)
{
return new Int64(x)-y;
}
Или же расписать на if.
V>>Опять же ХЗ зачем ты делаешь очередные ответвления от и так раздутых постов... S>Минуточку. Скоро всё станет ясно.
Блин, что за детсад? Мог бы не растягивать итерации, ты уже получил что хотел от меня изначально. Все поняли из условия, что ты хотел услышать, тебе это уже дали (выделенное).
V>>Вводится ф-ия сравнения f для домена ID {MIN_INT..MAX_INT, null} возвращающая результат в домене SQL_PREDICATE {true, false, null}. Дальше продолжать или уже понятно, с учетом сказанного в пред. посте? S>Ок, я понял вашу идею. Она заслуживает рассмотрения, хотя, скажем, сам Кодд почему-то был другого мнения, и построил расширение своей РА вместо сведения к дополнительным Join+Selection.
Наверно, чтобы не париться в частовстречающихся сценариях?
Его расширение так и осталось его расширением, кстате, т.е. не было включено в саму РА. Есть же еще 12 правил Кодда, которые даже не изучают в ВУЗах (максимум просто упоминают, в экзаменах этого нет, по крайней мере у нас не было, т.к. это уже во-многом прикладной уровень, игнорируемый нашим образованием). ИМХО, еще от того, что эти правила так и не были реализованы полностью в никакой СУБД.
V>>Наверно потому, что современные СУБД — это "вещь в себе", с дорогостоящей связью с внешним миром, т.е. требуется предоставить максимум ср-в внутри СУБД, чтобы писать разносторонние приложения. S>Удивительно, как это авторы SQL предусмотрели вот эту возможность писать "разносторонние приложения" сразу же из коробки — не дожидаясь, когда появятся разносторнние приложения и начнут требовать поддержки нереляционных данных. И всё ещё в 80х. Зато вот производительность серверов их никак не интересовала — во-времена то, когда 16 мегабайт памяти на машине были большой редкостью, а гигабайтные базы — нет.
Базы существовали еще до появления SQL, поэтому требования к "из коробки" были известны, ничего удивительного. Первые SQL шли как препроцессоры к обычным языкам программирования, поэтому народ привык, что вперемешку с реляционными операциями над данными он может совершать над ними произвольные прикладные операции. В общем, вопрос языковых ср-в малость отдельный, бо это нормально, когда язык поддерживает более одной парадигмы. Это не мешает исследовать сии парадигмы независимо.
V>>Как мы еще не дошли до обсуждения временных таблиц и императивных алгоритмов на курсорах? Непорядок, непорядок... S>Вы не переживайте, если потребуется — дойдём. V>>Далеко не всех, а лишь где задекларирована поддержка SQL-99. MySQL, MS Access, MS ESQL и т.д. не понимают. Да и не такое уж это и небольшое расширение. Стало возможным задавать запросы, непредставимые в терминах РИ. S>MS Access, простите, это настольная СУБД. Для промышленного использования она никогда и не предназначалась.
Давай вот это оставим в пользу бедных. В случае многозвенки, коль есть еще один выделенный сервер, любые in-proc движки данных, и даже MSJet, вполне подходящи. Конечно, речь не о клиенте к MSJet, которым является офисное приложение MS Access, но так уж принято называть этот движок по имени использующего приложения, ради которого он был разработан. Считай, что я поправился, хотя мне этого глубоко не принципиально.
S>А в SQL Server (всех редакций, включая Express) — есть.
При чем тут Express? В экспрессе фактически та же кодовая база, просто вложены ограничения. Имелся ввиду MS SQL Everywhere, который доступен теперь на десктопе как MS SQL CE, и показал себя весьма эффективным для случая подключения движка базы в виде in-proc. Экпрессу во многих сценариях до него как до Китая раком, в плане эффективности.
Теоретики реляционных баз данных в процессе развития теории...
Считается, что вокруг реляционных баз таки теория, а не просто инженерия.
V>>Делаются конкретные приложения. Ты снова и снова путаешь св-ва инструментария и характера данных. Не нужна тебе целостность — да не поддерживай, какие проблемы? V>>Мне важно обратное, что СУБД предоставляет все ср-ва для построения реляционной модели данных. S>Задам вам ваш любимый вопрос: что первично?
Первично реализация требований. Фишка в том, что реализовать требования в общем случае можно более, чем одним способом. Поэтому можно спекулировать отсюда и до бесконечности.
V>>Ну это да... чтобы производительность получения промежуточных результатов не волновала особо, для исторических есть отдельно стоящий OLAP, а оперативные не особо велики, по меркам современных машин. S>Ага. То есть в 1986 году авторы стандарта SQL заранее знали, что в 2011 будет отдельно стоящий OLAP, а оперативные данные будут не особо велики, по меркам современных машин.
Так делали еще до появления SQL. Это вроде изобретение банковских систем.
S>И с дьявольской предусмотрительностью сделали основой модели SQL мультимножества для того, чтобы сразу же колбасить на SQL-совместимых СУБД постреляционные приложения и дать в полный рост развернуться системам ORM.
Для хранения объектов вообще реляционные субд не айс. Просто пользуют из-за надежной реализации транзакций... ИМХО, сугубо исторически.
И при чем тут мой анализ? Реляционная теория занимается вопросами эффективной реализации внешнего хранилища. И не особо твои мультимножества мешают, хорош рефлексировать. Возьми свою ссылку по правилам преобразованиям РА и попытайся доказать, что эти преобразования для случая мультимножеств станут невалидными. Ты же утверждаешь, что их нельзя использовать в процессе оптимизации "реальных запросов", вот докажи в верифицируемом виде. Как докажешь, продолжишь тыкать в меня своими мультимножествами, а пока сделай паузу... Меня эта тема вообще не волнует, бо в самых первых вариантах в реляционной модели предлагалось снабдить кортежи неким порядковым номером (т.е. обязательным суррогатным ключом), потом от этого отказались. В реальных СУБД обязательно есть некий RowID, т.е. записи в любом случае различимы для самой СУБД, хоть тебе эта информация на прикладном уровне и не дается, ее можно посмотреть в трейсе. Именно поэтому меня твой аргумент насчет мультимножеств не особо торкает, он малость надуман спора ради.
S>>>Серъёзно что ли? Мне нравятся кванторы типа "практически всегда". Это вы себе лазейку оставляете для того, чтобы когда я вас носом ткну в реалистичный пример применения неуникального индекса, вы начали юлить типа "ой, ну это же так редко нужно"? Давайте вы вместо "практически всегда" напишете, когда именно "обыгрывание ключа дополнительным отношением" будет приводить к росту эффективности по сравнению с банальным create index. А когда, соответственно, наоборот.
V>>Когда будет — уже привел, это для случая кластерного неуникального индекса. S>То есть для "кластерного неуникального индекса" ваше "обыгрывание ключа дополнительным отношением" будет приводить к росту эффективности, я вас правильно понял?
Неправильно, ты потерял контекст. Наоборот, для этого случая и предлагалось резервировать кластерный индекс, коль он всего один, но такой сценарий есть. А остальное ты зря так смело скипнул, в нем сама первоначальная суть индексов в ограничении объема обрабатываемых данных (хоть речь шла об "искусственном" индексе). Есть еще фишка: по таблице кластерный индекс может быть только один, а такие "искусственные" индексы в виде отдельного отношения для прикладных сценариев могут иметь каждый свой кластерный индекс.
Здравствуйте, gandjustas, Вы писали:
G>Порядок вычислений и порядок композиции не одно и то же. Композиция не коммутативна, но никто не говорит что функция справа должна быть вычислена раньше, чем функция слева оператора композиции.
Тем не менее, для коммутативных операций это так. Но они составляют лишь подмножество обсуждаемого предмета.
Причем, коммутативность в случае РА существует на 2-х уровнях: в самих некоторых операциях РА (теоретико-множественных) и потенциально в аналитическом виде в функциях-условиях ограничений и продукций. Так вот, если в плане коммутативности самих операций РА никто спекулировать не решился, из-за, прямо скажем, потенциальной слабости аргумента, т.к. на виду и те операции, что не коммутативны... то наличие возможной коммутативности в аналитическом виде функций-ограничений легко пошло как аргумент, почему-то. По мне, одного поля ягоды. И там и там возможны некоммутативные операции, поэтому в общем случае перестановки операций будут менять семантику.
S>Волшебным образом в B-tree количество чтений определяется логарифмом количества занятых страниц, которое, в свою очередь, пропорционально N.
покажи переход от кол-ва чтений записей к кол-ву чтений страниц и далее к кол-ву операций чтений с винта.
чтение записей действительно логарифм, и действительно не зависит от размера страниц.
зы
если человек не может внятно написать формулу как взаимосвязано кол-во чтений записей с кол-вом чтений с винта, то о каком умении разделения абстракций вообще можно говорить...
S>Поэтому независимо от наличия постороннего наблюдателя имеет смысл избегать вопросов типа S>
S>если <заведомо ложный предикат> то <некий другой предикат>; объясните почему?
не перескакивай
обсуждалась тема "каким должен быть ответ"(а не каким должен быть вопрос), и была дана рекомендация: ответ должен быть таким, чтобы он мог быть перепроверен сторонним наблюдателем.
если ты утверждаешь, что вывод неверен, потому что неверна исходная посылка, значит ты должен в ответе(исходя из данной рекомандации) показать ложность вводного утверждения, а не посылать читать букварь (первое перепроверяемо сторонним наблюдателем, во втором случае — перепроверять нечего).
S>Не нравится вам библия — давайте я так спрошу: "если кирпич — жидкость, то почему мы строим стены из бетона"?
здесь как раз нет ложных посылок.
здесь вводится допущение, которое как раз может быть произвольным. и заключается в формулировании предположения(гипотезы), которое временно считается верным.
1. например, в математике — значительная часть доказательств начинается с допущений, в частности, все доказательства от противного делаются через предварительное допущение, которое считается верным.
2. также, например, стойкость значительной части криптографии доказывается через допущение, что NP != P (которое само по себе недоказано) и т.д.
3. допущение также может использоваться для упрощения формул. Например, используется допущение, что 0! = 1, это упрощает значительную часть формул комбинаторики.
4. частным случаем допущений являются аксиомы. например, евклидова геометрия отличается от геометрии лобачевского лишь допущением: параллельные прямые пересекаются или нет;
5. на допущениях строится значительная часть наук. геометрическая оптика использует допущение, что свет — это частица(луч);
большая часть физики использует допущение, что тело можно представить как материальную точку; и т.д.
и соответственно, нет разницы между допущениями:
допустим, что человек — точка
допустим, что кирпич — жидкость
они оба строго говоря не верные.
фраза "допустим, что A — X" означает, давайте временно наделим понятие A свойствами X, и сделаем выводы, которые из этого следует.
Первое допущение наделяет человека свойством, что его размеры равны 0,
второе допущение может, например, наделять кирпич свойствами что его можно передавать по трубам.
Готовые построенные выводы дадут понимание в реальной задаче, а что даст хорошего — если удастся человека посчитать точкой, или что будет хорошо, если кирпич удастся передавать по трубам? и соответственно дают ответ на вопрос — а нужно ли вообще стремиться считать человека точкой? или нужно ли стремиться передавать кирпичи по трубам?
допущения используются для разбиения задачи на части (что часто используется когда в задаче присутствует высокая вариативность, неопределенность, разнородность и т.д.).
решение задачи "верно ли, что из A следует Z" заменяется на ряд временных задач:
задача 1. верно ли что из A следует B? ;
задача 2. допустим, что верно B. верно ли что из B следует C?
..
вместо задачи "верно ли, что из A следует Z", может быть любой другой вид задач: можно ли из A построить Z; верно ли, что A меньше Z и т.д
при этом решение задачи может двигаться с наиболее определенных подзадач, или с подзадач, которые сильнее всего уменьшают вариативность и т.д.
S>Я вам советую по возможности избегать математики. Там везде сплошная религия. Берут, скажем, набор требований, и называют конструкцию, которая этим требованиям удовлетворяет, полем.
так в том-то и дело, что полем при этом будет являться произвольная штука, которая обладает данными требованиями.
в том числе и штука, для которой удалось доопределить, допустить и т.д. данные требования.
также при этом на само название всем пофигу, его можно называть хоть грядкой: главное, что если что-то удовлетворяет данным требованиям, то оно будет всегда обладать следующими свойствами:
Характеристика поля всегда 0 или простое число. Поле характеристики 0 содержит подполе, изоморфное полю рациональных чисел .
Поле простой характеристики p содержит подполе, изоморфное полю вычетов .
Количество элементов в конечном поле всегда равно pn — степени простого числа. При этом для любого числа вида pn существует единственное (с точностью до изоморфизма) поле из pn элементов, обычно обозначаемое .
Любой ненулевой гомоморфизм полей является вложением.
В поле нет делителей нуля.
при этом все эти свойства доказываются, и соответственно, можно показать, как будут меняться эти свойства, если меняются исходные требования.
другими словами: слово поле — это лишь синоним для "множество F с двумя бинарными операциями + (аддитивная операция, или сложение) и (мультипликативная операция, или умножение), если оно (вместе с этими операциями) образует коммутативное ассоциативное кольцо c единицей , все ненулевые элементы которого обратимы"
и само слово поле можно выкинуть
соответственно, математическое определение объекта — это, например:
объект — это штука которая обладает следующими требованиями: есть функция идентичности, есть посылка/прием сообщений.
именно такое математическое определение я и просил.
и исходя из определения выше, переменная является объектом — для случая, когда функцией идентичности является индентичность экземпляров переменной, а сообщениями является установка и получения значения из переменной.
S>Ни тебе связи с реальностью;
есть связь с реальностью: указано, что комплексные, вещественные, рациональные числа являются полем.
S> ни тебе доказательства того, что без дистрибутивности поле не работает.
если ты откроешь учебник, там будет это доказательство.
и будет доказано, что из требований "множество F с двумя бинарными операциями + (аддитивная операция, или сложение) и (мультипликативная операция, или умножение), если оно (вместе с этими операциями) образует коммутативное ассоциативное кольцо c единицей , все ненулевые элементы которого обратимы."
всегда следует, что "это есть коммутативная группа по сложению, а все его ненулевые элементы образуют коммутативную группу по умножению, и выполняется свойство дистрибутивности".
S>А то и вообще — как начнут выписывать аксиомы типа "через точку можно провести ровно одну прямую, параллельную данной", опираясь на понятие прямой, которого в реальности не существует.
вообще-то определения прямой действительно нету, это неопределяемое понятие. у неопределяемых понятий бывает лишь описание и свойства.
Здравствуйте, vdimas, Вы писали:
V>Ну тогда можно сразу завязывать с ничьей, т.к. математическая нотация изначально слабо относится к парадигмам программирования, если быть строгим, т.е. обсуждение ни о чем.
Согласен.
V>Уже показал на примере Cross production selection, где аналитический вид ф-ии ограничения считается известным, поэтому всё преобразование свелось к декомпозиции самой ф-ии ограничения и применения разных ее частей на разных этапах. Так вот, РА не занимается исследованием декомпозиций аналитических ф-ий, поэтому, хоть и показаны преобразования формул РА, это происходит не на уровне РА, а над ним.
Ну то есть мы начинаем постепенно понимать, что оптимизатор запросов в СУБД работает не на уровне РА. Это хорошо.
V>Это как раз случай явной выразимости одних операций через другие, т.е. таких, где не требуется знание аналитического вида формул.
Каких одних через какие другие?
V>К тому же, про этот случай сказал в предыдущем сообщении, и его физический смыл был раскрыт в следующих строчках по твоей же ссылке: V> V>Операция AND в условиях выборки коммутативна, поэтому да. Даи это было лишнее для аргументации. Ведь часть операций РА, которые являются теоретико-множественными, коммутативны сами по себе, поэтому можно было просто привести вот так еще в самом начале: V>A AND (B AND C) = (A AND B) AND C. V>A OR (B OR C) = (A OR B) OR C. V>Где A,B,C — совместимые отношения. Сразу бы и отделили коммутативные от некоммутативных, чтобы не обобщать огульно.
Вы путаете коммутативность с ассоциативностью.
V>Нет, не поэтому, а исключительно из-за коммутативности. Аналогично вычислениям над обычными числами даже в императивной программе, часть вычислений можно проводить в произвольном порядке, если речь идет о коммутативных равноприоритетных операцих.
Вы ошибаетесь. Возьмём, к примеру, коммутативную операцию над обычными числами:
int i = GetA()*GetB();
Если у GetA() или GetB() есть побочный эффект, то перестановка порядка вычислений запрещена. Несмотря на коммутативность умножения.
Другой пример — возьмём умножение матриц:
Matrix i = GetA()*GetB();
Если у GetA() и GetB() гарантированно нет побочных эффектов, то можно вычислять их в любом порядке. Несмотря на отстутствие коммутативности.
V>РА не занимается семантикой, это делается на уровне РИ и реляционной модели. Т.е., чтобы провести все те преобразования формул РА, помимо заведомо коммутативных преобразований (т.е. безусловным образом выразимых через друг друга),
Алиса, никогда не употребляй слова только за то, что они длинные и красивые. Погуглите определение термина "коммутативность".
V>>>Он важен точно так же, так же как для классичесского функционального программирования, где вышестоящие ф-ии используют результаты нижестоящих. S>>Совершенно верно. Но ведь это не делает "классическое функциональное программирование" императивным.
V>Возможно, хотя может сделать его процедурным, если мы не используем первоклассные ф-ии, не?
Не, не может. V>А процедурный подход относится к императивному или нет? Мне таки интересно твое развернутое мнение. Таки машина Тьюринга описана как автомат с ленточной памятью.
А частично рекурсивные функции — нет. Дальше что?
V>Ну коль для кластерного индекса строится точно такое же дерево на уровне неличтовых страниц, то чем он отличается от некластерного, когда на странице будет всего одна запись?
Тем, что для некластерного таки будет создана отдельная страница. Вы не стесняйтесь, читайте литературу. V>Вообще, надо поднять тот проект, посмотреть, почему после отказа от кластерных индексов по primary_key резко возросло общее быстродействие... Возможно, что по коссвенным к обсуждаемому причинам, например доступности теперь кластерного для внешних ключей.
Конечно по косвенным. Но вы поспешили сделать выводы. V>Насчет порядка: если некая соединительная операция из 3-х (грубо) составляющий выполняется в 4 раза быстрее, что каждая в среднем стала выполняться быстрее в корень 3-й степени из 4.
Простите, но зачем вы продолжаете это делать? Времена выполнения операции Join очень косвенно связаны с произведением кардинальностей аргументов.
Например, merge join вообще выполняется как O(N+M).
S>>Да нет же, не используется. V>Врет ссылка?
Скажем так: упрощает. V>Для удобства в MS Access после проверки этого выражения проверь вот это: V>SELECT (TRUE AND (5 > NULL)) IS NULL
Ок, я понял. Ваш опыт, которым вы так гордитесь, получен в основном на настольной СУБД.
V>Определена как отношение, в котором присутствует атрибут x1 по тому же домену, что и атрибут y1 в отношении Y. V>Это я про то, что порядок и вид выражений РА вовсе не обязан соответствовать "естественному" порядку исходного SQL. И еще про то, что SQL крайне избыточен, позволяя задавать одни и те же запросы очень многими способами. Так вот, из приведения всех вариантов запросов к одному (для данного случая) варианту в терминах РА следует, что вид операций РА слабо связан с видом выражения в SQL.
Ок, хорошо, разница между РА и SQL становится всё более явной.
V>>>Если речь о "простой арифметике", то бишь о числах, то можно два варианта: поменять местами x и y согласно условия задачи (сортировки в обратном порядке), либо воспользоваться св-вом коммутативности числовой алгебры и просто поменять знак результата исходного компаратора, коль будет известно, что результат сравнения чисел реализован через вычитание. Если характер сравниваемых величин неизвестен, то остается первый способ, согласно условию. S>>Ок, пусть у нас результат сравнения чисел реализован через вычитание. Я правильно понял из выделенного, что вы считаете вот такую реализацию корректной для "обычных" int32?
V>До сегодняшнего дня да, коль (x-y)==-(y-x). V>Но у тебя ошибка в коде, нет учета переполнения.
Воот. Эта ошибка связана с тем, что код предполагает такую же математику в компьютере, как и в учебнике. В учебнике у всех целых чисел есть их "антипод", -x = -1*x.
А в компьютере — не у всех, разрядность ограничена.
И можно действовать двумя способами:
а) привести задачу к "условиям теории", чтобы можно было использовать весь теоретический аппарат
б) привести решение к "специфике реализации", чтобы использовать тот аппарат, который есть на практике.
В первом варианте мы начинаем требовать от компьютера поддержки целых чисел произвольной разрядности; во втором — подпиливаем код так, чтобы он корректно работал с учётом ограничений, несмотря на то, что он выглядит не как "теоретическое" решение.
Вы пошли по второму варианту.
Но для реляционной модели и SQL вы продолжаете настаивать на первом варианте.
V>Его расширение так и осталось его расширением, кстате, т.е. не было включено в саму РА. Есть же еще 12 правил Кодда, которые даже не изучают в ВУЗах (максимум просто упоминают, в экзаменах этого нет, по крайней мере у нас не было, т.к. это уже во-многом прикладной уровень, игнорируемый нашим образованием). ИМХО, еще от того, что эти правила так и не были реализованы полностью в никакой СУБД.
V>>>Наверно потому, что современные СУБД — это "вещь в себе", с дорогостоящей связью с внешним миром, т.е. требуется предоставить максимум ср-в внутри СУБД, чтобы писать разносторонние приложения. S>>Удивительно, как это авторы SQL предусмотрели вот эту возможность писать "разносторонние приложения" сразу же из коробки — не дожидаясь, когда появятся разносторнние приложения и начнут требовать поддержки нереляционных данных. И всё ещё в 80х. Зато вот производительность серверов их никак не интересовала — во-времена то, когда 16 мегабайт памяти на машине были большой редкостью, а гигабайтные базы — нет.
V>Базы существовали еще до появления SQL, поэтому требования к "из коробки" были известны, ничего удивительного. Первые SQL шли как препроцессоры к обычным языкам программирования, поэтому народ привык, что вперемешку с реляционными операциями над данными он может совершать над ними произвольные прикладные операции. В общем, вопрос языковых ср-в малость отдельный, бо это нормально, когда язык поддерживает более одной парадигмы. Это не мешает исследовать сии парадигмы независимо.
V>>>Как мы еще не дошли до обсуждения временных таблиц и императивных алгоритмов на курсорах? Непорядок, непорядок... S>>Вы не переживайте, если потребуется — дойдём. V>>>Далеко не всех, а лишь где задекларирована поддержка SQL-99. MySQL, MS Access, MS ESQL и т.д. не понимают. Да и не такое уж это и небольшое расширение. Стало возможным задавать запросы, непредставимые в терминах РИ. S>>MS Access, простите, это настольная СУБД. Для промышленного использования она никогда и не предназначалась.
V>Давай вот это оставим в пользу бедных. В случае многозвенки, коль есть еще один выделенный сервер, любые in-proc движки данных, и даже MSJet, вполне подходящи. Конечно, речь не о клиенте к MSJet, которым является офисное приложение MS Access, но так уж принято называть этот движок по имени использующего приложения, ради которого он был разработан. Считай, что я поправился, хотя мне этого глубоко не принципиально.
S>>А в SQL Server (всех редакций, включая Express) — есть.
V>При чем тут Express? В экспрессе фактически та же кодовая база, просто вложены ограничения. Имелся ввиду MS SQL Everywhere, который доступен теперь на десктопе как MS SQL CE, и показал себя весьма эффективным для случая подключения движка базы в виде in-proc. Экпрессу во многих сценариях до него как до Китая раком, в плане эффективности.
V>MySQL? SQLite?
Мускул, простите, не показатель. В нём вообще много чего ещё нет. А встраиваемые и настольные базы данных я предлагаю не рассматривать — они не для промышленного применения, поэтому в них все новшества появляются с большим опозданием.
V>Считается, что вокруг реляционных баз таки теория, а не просто инженерия.
Да это-то я понимаю. Мне было интересно, что именно вы под этим словом понимаете. Потому что вы имеете трогательную привычку использовать термины неожиданным образом.
V>Первично реализация требований.
Ну вот видите. А теоретические модели — они появляются потом, когда мы анализируем решения, удовлетворяющие требованиям. S>>И с дьявольской предусмотрительностью сделали основой модели SQL мультимножества для того, чтобы сразу же колбасить на SQL-совместимых СУБД постреляционные приложения и дать в полный рост развернуться системам ORM. V>Для хранения объектов вообще реляционные субд не айс. Просто пользуют из-за надежной реализации транзакций... ИМХО, сугубо исторически.
Конечно исторически. Просто кроме RDBMS на рынке ничего промышленно-надёжного так и не появилось. Успели выдавить в своё время.
V>Неправильно, ты потерял контекст.
Тогда напишите, как правильно. Когда именно лучше обыгрывать неуникальный ключ дополнительным отношением, вместо банального создания индекса?
Первоначальная суть индексов — в уменьшении количества обращений к диску.
Ограничение объёма данных — это один из способов добиться этого уменьшения, причём не самый эффективный.
V>Есть еще фишка: по таблице кластерный индекс может быть только один, а такие "искусственные" индексы в виде отдельного отношения для прикладных сценариев могут иметь каждый свой кластерный индекс.
Вы рассматривайте всю картину в целом. Сравните накладные расходы на неуникальный индекс и на "отдельное отношение" — даже если в этом отдельном отношении есть кластерный индекс.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>Волшебным образом в B-tree количество чтений определяется логарифмом количества занятых страниц, которое, в свою очередь, пропорционально N.
DG>покажи переход от кол-ва чтений записей к кол-ву чтений страниц и далее к кол-ву операций чтений с винта.
1. Операции "чтение записей" нет. Читаются всегда цельные страницы.
2. Размер страниц — фикирован, и не зависит от размера записей.
Что именно вам непонятно?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>а теперь сделай переход к вероятностям: вероятность того, что та или иная страница уже лежит в кэше, а также как будет выражено время выполнения запроса через вероятность нахождения тех или иных страниц в кэше. DG>зы DG>например, если ОП хватает, чтобы non-leaf pages в основном лежали в кэше (а так обычно и бывает), то производительность будет определяться в первую очередь как много надо прочитать leaf-pages, чтобы получить ответ. DG>соответственно, чем меньше записей лежит на одной leaf-pages, то тем больше надо прочитать страниц всего, а также тем выше вероятность нарваться на фрагментацию.
B-tree устроено так, что для любого поиска одиночного элемента надо прочитать ровно одну leaf-страницу.
Вероятности нахождения страниц в кэше крайне плохо поддаются предсказанию — как я уже сказал, там есть очень много факторов, которые вы так просто не учтёте.
Поэтому при оптимизации запросов уменьшают количество логическихчтений.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>здесь как раз нет ложных посылок. DG>здесь вводится допущение, которое как раз может быть произвольным. и заключается в формулировании предположения(гипотезы), которое временно считается верным.
ОМГ. Вижу, аллегории плохо доходят.
Вы "временно допускаете верным" предположения типа "вот эта функция является корректным переводом функции из одной системы в другую".
При этом никаких критериев корректности вы не приводите.
Зато предлагаете объяснить, почему другая пара функций не является корректным переводом друг друга.
Чего вы ожидаете в ответ? Чего-то проверяемого сторонним наблюдателем?
Вот вам ответ, проверяемый сторонним наблюдателем: из вашего единичного примера корректного перевода невозможно однозначно определить систему критериев корректности перевода таким образом, чтобы второй пример перевода был заведомо некорректным.
Если бы вы взяли на себя труд подготовить другую структуру вопроса — например, привели бы доказательство (или хотя бы его схему) того, что перевод корректен, то сторонний наблюдатель мог бы вам ответить, применив те же правила проверки корректности, что и вы к первому переводу.
А так — разгадывать ваши головоломки мотивации нет.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>Я вам советую по возможности избегать математики. Там везде сплошная религия. Берут, скажем, набор требований, и называют конструкцию, которая этим требованиям удовлетворяет, полем.
DG>так в том-то и дело, что полем при этом будет являться произвольная штука, которая обладает данными требованиями.
Правильно. Ну так вам и твердят: объектом называется сущность, которая обладает идентичностью, поведением, и состоянием. А вы зачем-то начинаете мучить мозг и спрашивать, почему нельзя называть объектом то, что этим требованиям не удовлетворяет. Ну не удовлетворяет — и слава байту; ООП — вовсе не единственная модель программирования.
На immutable-структурах без идентичности можно построить ничуть не менее выразительную и мощную модель. Можно вообще обойтись без каких-либо структур, одними только функциями.
Убирая те или иные свойства из модели ООП вы будете получать другие, несовместимые с ООП модели.
Добавляя свойства, вы можете построить развитую ООП-модель. Никто не против. Добавьте классы, наследование, понятие идемпотентных и безопасных методов, добавьте понятия негарантированной доставки и стоимости доставки сообщений. Всё — по вкусу. Но эти элементы не обязательны.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>так в том-то и дело, что полем при этом будет являться произвольная штука, которая обладает данными требованиями. S>Правильно. Ну так вам и твердят: объектом называется сущность, которая обладает идентичностью, поведением, и состоянием. А вы зачем-то начинаете мучить мозг и спрашивать, почему нельзя называть объектом то, что этим требованиям не удовлетворяет.
так переменная объект или нет?
у нее есть идентичность, поведение и состояние.
S>Вероятности нахождения страниц в кэше крайне плохо поддаются предсказанию — как я уже сказал, там есть очень много факторов, которые вы так просто не учтёте.
в данном случае, необходимо предсказать другую величину, а именно отношение вероятностей нахождения в кэше страниц кластерного индекса и вероятность нахождения в кэше страниц некластерного индекса.
соответственно, можно считать, что все остальные факторы взаимоуничтожаются
DG>>так в том-то и дело, что полем при этом будет являться произвольная штука, которая обладает данными требованиями. S>Правильно. Ну так вам и твердят: объектом называется сущность, которая обладает идентичностью, поведением, и состоянием. А вы зачем-то начинаете мучить мозг и спрашивать, почему нельзя называть объектом то, что этим требованиям не удовлетворяет.
ты пропустил несколько важных моментов:
во-первых, с точки зрения математики, если чего-то не хватает, то это можно доопределить.
например, функция x2/x не является ни гладкой, ни непрерывной на всем интервале, но можно доопределить ей в точке 0 значение и производную, и она станет гладкой и непрерывной на всем интервале
во-вторых, с точки зрения математике, если, например, всё множество полем не является, то можно рассмотреть отдельные подмножества, которые являются полями, а потом на основе этого сделать вывод на основе всего множества.
отсюда и появляется, что если что-то не является объектом на на всём множестве операций, это можно рассмотреть на отдельных множествах операций когда это что-то является объектом, а потом сделать выводы и для что-то целиком.
Здравствуйте, DarkGray, Вы писали:
DG>во-первых, с точки зрения математики, если чего-то не хватает, то это можно доопределить.
Это всё понятно. Но вы хотите не "доопределить", а "недоопределить". То есть начинаете с функции y=1, а потом убираете у неё в несчётном множестве точек значение и производную, а потом удивляетесь, что её не хотят признавать гладкой и непрерывной. DG>во-вторых, с точки зрения математике, если, например, всё множество полем не является, то можно рассмотреть отдельные подмножества, которые являются полями, а потом на основе этого сделать вывод на основе всего множества.
Это интересно как? То есть мы берём, скажем, подмножество дифференцируемых интегрируемых функций, доказываем для него что-нибудь, а потом говорим "а, ну наверное всё то же приложимо и ко множеству вообще всех функций", так что ли? Весьма неожиданный ход.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Это интересно как? То есть мы берём, скажем, подмножество дифференцируемых интегрируемых функций, доказываем для него что-нибудь, а потом говорим "а, ну наверное всё то же приложимо и ко множеству вообще всех функций", так что ли? Весьма неожиданный ход.
берем множество, разбиваем его на подмножества — для каждого подмножества доказываем следствие своим способом, и в результате делаем вывод, что все множество имеет данное следствие.
из этого в частности следует, что множество не обязано быть однородным, чтобы иметь то или иное следствие.
а из этого следует, что программа может быть ООП-программой, даже если объекты в ней выделяются разными способами, и используются различные функции идентичности для различных объектов (если при этом ее можно достроить под требования ООП).
DG>>норма — это "усредненние" ожиданий членов группы, и здесь еще добавляется неопределенность от того, что можно взять разный способ "усреднения", а так же можно по разному брать группу, и соответственно норма имеет более высокую неопределенность, чем ожидание S>Ожидание члена группы — без указания конкретного индивидума еще более неопределено чем усреднение ожиданий членов группы, т.е. норма.
больше всего определенности в конкретных произошедших фактах, и соответственно самые определенные — это ожидания конкретного индивидуума в конкретной ситуации.
Здравствуйте, DarkGray, Вы писали:
DG>во-первых, с точки зрения математики, если чего-то не хватает, то это можно доопределить.
Как Хоттабыч доопределил мячей по числу футболистов?
DG>например, функция x2/x не является ни гладкой, ни непрерывной на всем интервале, но можно доопределить ей в точке 0 значение и производную, и она станет гладкой и непрерывной на всем интервале
Не понял, о какой функции идет речь. Но с точки зрения матемтики, если ты доопределил функцию, то ты получил доопределенную функцию, высказывания на счет которой не распространяются на исходную функцию в общем случае.
DG>во-вторых, с точки зрения математике, если, например, всё множество полем не является, то можно рассмотреть отдельные подмножества, которые являются полями, а потом на основе этого сделать вывод на основе всего множества.
Не понял. Множество полем не является, но существуют подмножества, являющиеся полями, причем объединение подмножеств является исходным множеством? Можно пример?
DG>отсюда и появляется, что если что-то не является объектом на на всём множестве операций, это можно рассмотреть на отдельных множествах операций когда это что-то является объектом, а потом сделать выводы и для что-то целиком.
Если что-то не обладает неким свойством на некотором множестве, то значит существуют элементы множества, на которых это что-то не обладает неким свойством. Пардон за тавтологию. Но что бы ты не рассматривал, это что-то на таких элементах обладать данным свойством не станет.
DG>>например, функция x2/x не является ни гладкой, ни непрерывной на всем интервале, но можно доопределить ей в точке 0 значение и производную, и она станет гладкой и непрерывной на всем интервале S>Не понял, о какой функции идет речь. Но с точки зрения матемтики, если ты доопределил функцию, то ты получил доопределенную функцию, высказывания на счет которой не распространяются на исходную функцию в общем случае.
так высказывания про исходную функцию при решении конкретной задаче часто никому и не нужны.
DG>>во-вторых, с точки зрения математике, если, например, всё множество полем не является, то можно рассмотреть отдельные подмножества, которые являются полями, а потом на основе этого сделать вывод на основе всего множества. S>Не понял. Множество полем не является, но существуют подмножества, являющиеся полями, причем объединение подмножеств является исходным множеством? Можно пример?
я говорил о конкретном выводе: например, что для всего множества сохраняется закон дистрибутивности.
DG>>отсюда и появляется, что если что-то не является объектом на на всём множестве операций, это можно рассмотреть на отдельных множествах операций когда это что-то является объектом, а потом сделать выводы и для что-то целиком. S>Если что-то не обладает неким свойством на некотором множестве, то значит существуют элементы множества, на которых это что-то не обладает неким свойством. Пардон за тавтологию. Но что бы ты не рассматривал, это что-то на таких элементах обладать данным свойством не станет.
ты сейчас это рассматриваешь с точки зрения логики существования, а не с точки зрения конструирования.
если нам дано сложное множество, то изначально мы не знаем существует или нет для него следствие, и это знание появится только в результате конструирования доказательства (при котором множество и разбивается на подмножества про которые известно: существует или нет следствие)
тоже самое и с программой: глядя на сложную программу мы не можем, глядя в потолок, сделать конкретный вывод: программа является или не является ООП-программой, сначала необходимо сконструировать доказательство, которое покажет, что это программа ООП или не ООП. при этом если мы не можем построить способ рассмотрения данной программы как ООП-программы, из этого не следует, что никто не может. поэтому я часто и делаю замечание Sinclair-у, что он делает слишком поспешные негативные выводы (которые неверны с точки зрения конструктивной логики).
S>Вместо этого будет достаточно эквивалентности, определённой как совпадение состояний.
как это можно использовать, например, при показе того, почему следующий код неверный?
//суммирует квадраты чисел по всей последовательности
function double SquareSum(IEnumerable<double> numbers)
{
var lazyNumbers = new List<Func<double>>();
foreach (var x in numbers)
lazyNumbers = ()=> x*x;
return lazyNumbers.Sum(lazy => lazy());
}
вызов SquareSum(new[]{1, 2}) выдает 8 (хотя должен выдавать 5)
ps
через использование идентичности и трасс можно показать, почему этот код неверный.
DG>>>например, функция x2/x не является ни гладкой, ни непрерывной на всем интервале, но можно доопределить ей в точке 0 значение и производную, и она станет гладкой и непрерывной на всем интервале S>>Не понял, о какой функции идет речь. Но с точки зрения матемтики, если ты доопределил функцию, то ты получил доопределенную функцию, высказывания на счет которой не распространяются на исходную функцию в общем случае.
DG>так высказывания про исходную функцию при решении конкретной задаче часто никому и не нужны.
Но ты их совершил. См. выделенное.
Или тут у тебя тот же фокус, что с сохранением идентичности строк при сложении?
DG>>>во-вторых, с точки зрения математике, если, например, всё множество полем не является, то можно рассмотреть отдельные подмножества, которые являются полями, а потом на основе этого сделать вывод на основе всего множества. S>>Не понял. Множество полем не является, но существуют подмножества, являющиеся полями, причем объединение подмножеств является исходным множеством? Можно пример?
DG>я говорил о конкретном выводе: например, что для всего множества сохраняется закон дистрибутивности.
согласен на конкретный пример дистрибутивного множества, не являющегося полем, но содержащим поля в качестве подмножеств. Так что дистрибутивность множества вытекает из дистрибутивности его подмножеств полей.
DG>>>отсюда и появляется, что если что-то не является объектом на на всём множестве операций, это можно рассмотреть на отдельных множествах операций когда это что-то является объектом, а потом сделать выводы и для что-то целиком. S>>Если что-то не обладает неким свойством на некотором множестве, то значит существуют элементы множества, на которых это что-то не обладает неким свойством. Пардон за тавтологию. Но что бы ты не рассматривал, это что-то на таких элементах обладать данным свойством не станет.
DG>ты сейчас это рассматриваешь с точки зрения логики существования, а не с точки зрения конструирования. DG>если нам дано сложное множество, то изначально мы не знаем существует или нет для него следствие, и это знание появится только в результате конструирования доказательства (при котором множество и разбивается на подмножества про которые известно: существует или нет следствие)
Ты же написал что что-то не является объектом на всем множестве операций. Это не вопрос. Это утверждение. Т.е. ты не исследуешь эту ситуацию, для тебя это свершившийся факт. Но путем разбиения всего множества на какие-то части ты этот факт выворачиваешь. Вот это мне странно.
DG>тоже самое и с программой: глядя на сложную программу мы не можем, глядя в потолок, сделать конкретный вывод: программа является или не является ООП-программой, сначала необходимо сконструировать доказательство, которое покажет, что это программа ООП или не ООП. при этом если мы не можем построить способ рассмотрения данной программы как ООП-программы, из этого не следует, что никто не может. поэтому я часто и делаю замечание Sinclair-у, что он делает слишком поспешные негативные выводы (которые неверны с точки зрения конструктивной логики).
Мне неизвестны формальные критерии принадлежности конкретной программы к ООП. Но известно что ты пока не смог предоставить непротиворечивую идентичность для того что бы рассматривать строки "с версионной иммутабельностью" и переменные как объекты.
DG>>я говорил о конкретном выводе: например, что для всего множества сохраняется закон дистрибутивности. S>согласен на конкретный пример дистрибутивного множества, не являющегося полем, но содержащим поля в качестве подмножеств. Так что дистрибутивность множества вытекает из дистрибутивности его подмножеств полей.
возьмем множество состоящее из множества рациональных чисел и спец. элемента inf; элемент такого множества будет называть ri
определим операцию + как:
+ для рациональных чисел такой же как + для исходного множества рациональных чисел
+ (inf, inf) = inf
+ (рац. числа, inf) и (inf, рац. числа) = inf
операцию * как:
* для рациональных чисел такой же как * для исходного множества рациональных чисел
* (inf, inf) = inf
* (рац. числа, inf) и (inf, рац. числа) = inf
докажем, что операции +/* дистрибутивны для всего множества [рац. числа; inf]:
op есть операция из множества [+,*]
следствие 1: op(ri, inf) = op(inf, ri) = inf
следствие 2: op(ri, inf) — коммутативна и ассоциативна из следствия 1
следствие 3:операции +,* коммутативны и ассоциативны для любой пары (ri, ri), т.к. пара (рац. число, рац. число) — коммутативная и ассоциативная из-за того, что рац. числа — поле, а остальные три пары представимы как (ri, inf) и коммутативны и ассоциативны на основе следствия 2
тройка (ri, ri, ri) дистрибутивна относительно операций +/-, потому что:
(рац. число, рац. число, рац. число) дистрибутивна, потому что рац. числа — поле
(inf, ri1, ri2) — дистрибутивна, потому что inf*(ri1 + ri2) = inf*(ri') = inf, а inf*ri1 + inf*ri2 = inf+inf = inf
(ri1, inf, ri2) дистрибутивна, потому что ri1*(inf + ri2) = ri1 *inf = inf, а ri1*inf + ri1*ri2 = inf + ri' = inf
(ri1, ri2, inf) дистрибутивна, потому что дистрибутивна (ri1, inf, ri2), а операция + коммутативна
дистрибутивность справа вытекает на основании следствия 3
DG>>ты сейчас это рассматриваешь с точки зрения логики существования, а не с точки зрения конструирования. DG>>если нам дано сложное множество, то изначально мы не знаем существует или нет для него следствие, и это знание появится только в результате конструирования доказательства (при котором множество и разбивается на подмножества про которые известно: существует или нет следствие) S>Ты же написал что что-то не является объектом на всем множестве операций. Это не вопрос. Это утверждение. Т.е. ты не исследуешь эту ситуацию, для тебя это свершившийся факт. Но путем разбиения всего множества на какие-то части ты этот факт выворачиваешь. Вот это мне странно.
при конструировании сложных вещей появляются куча элементов, которые почти такие же как исходные, но имеют какие-то добавочные свойства. при строгих выводах эти все добавочные элементы необходимо обозначать другими символами, но мне не хочется это делать на форуме из-за громоздкости.
DG>>тоже самое и с программой: глядя на сложную программу мы не можем, глядя в потолок, сделать конкретный вывод: программа является или не является ООП-программой, сначала необходимо сконструировать доказательство, которое покажет, что это программа ООП или не ООП. при этом если мы не можем построить способ рассмотрения данной программы как ООП-программы, из этого не следует, что никто не может. поэтому я часто и делаю замечание Sinclair-у, что он делает слишком поспешные негативные выводы (которые неверны с точки зрения конструктивной логики). S>Мне неизвестны формальные критерии принадлежности конкретной программы к ООП. Но известно что ты пока не смог предоставить непротиворечивую идентичность для того что бы рассматривать строки "с версионной иммутабельностью" и переменные как объекты.
есть множество [строки, другие объекты]:
функция идентичности для данного множества
для [строка, строка] = equals(строка, строка)
для [строка, другой объект] = false
для [другой объект, другой объект] = referenceequals(другой объект, другой объект)
S>Это всё понятно. Но вы хотите не "доопределить", а "недоопределить". То есть начинаете с функции y=1, а потом убираете у неё в несчётном множестве точек значение и производную, а потом удивляетесь, что её не хотят признавать гладкой и непрерывной.
так если в конкретной задаче эти точки не используются, то можно на этих точках функцию доопределить как угодно.
и соответственно, возникает меньшая проблема: можно ли решить конкретную задачу без использования этих точек?
если можно, то значит для данной конкретной задачи можно считать, что функция y=1 с дырками гладкая и непрерывная на всем интервале в данной задаче.
тоже самое и с идентичностью:
если в программе нигде не используется являются ли объекты x,y идентичными или нет, то нет и необходимости, чтобы функция идентичности была определена на этой паре, т.к. всегда можно для этой пары доопределить функцию идентичности как хочется, все равно это ни на что не повлияет.
DG>>>я говорил о конкретном выводе: например, что для всего множества сохраняется закон дистрибутивности. S>>согласен на конкретный пример дистрибутивного множества, не являющегося полем, но содержащим поля в качестве подмножеств. Так что дистрибутивность множества вытекает из дистрибутивности его подмножеств полей.
DG>возьмем множество состоящее из множества рациональных чисел и спец. элемента inf; элемент такого множества будет называть ri DG>определим операцию + как: DG> + для рациональных чисел такой же как + для исходного множества рациональных чисел DG> + (inf, inf) = inf DG> + (рац. числа, inf) и (inf, рац. числа) = inf DG>операцию * как: DG> * для рациональных чисел такой же как * для исходного множества рациональных чисел DG> * (inf, inf) = inf DG> * (рац. числа, inf) и (inf, рац. числа) = inf DG>докажем, что операции +/* дистрибутивны для всего множества [рац. числа; inf]: DG>op есть операция из множества [+,*] DG>следствие 1: op(ri, inf) = op(inf, ri) = inf DG>следствие 2: op(ri, inf) — коммутативна и ассоциативна из следствия 1 DG>следствие 3:операции +,* коммутативны и ассоциативны для любой пары (ri, ri), т.к. пара (рац. число, рац. число) — коммутативная и ассоциативная из-за того, что рац. числа — поле, а остальные три пары представимы как (ri, inf) и коммутативны и ассоциативны на основе следствия 2 DG>тройка (ri, ri, ri) дистрибутивна относительно операций +/-, потому что: DG>(рац. число, рац. число, рац. число) дистрибутивна, потому что рац. числа — поле DG>(inf, ri1, ri2) — дистрибутивна, потому что inf*(ri1 + ri2) = inf*(ri') = inf, а inf*ri1 + inf*ri2 = inf+inf = inf DG>(ri1, inf, ri2) дистрибутивна, потому что ri1*(inf + ri2) = ri1 *inf = inf, а ri1*inf + ri1*ri2 = inf + ri' = inf DG>(ri1, ri2, inf) дистрибутивна, потому что дистрибутивна (ri1, inf, ri2), а операция + коммутативна DG>дистрибутивность справа вытекает на основании следствия 3
Схема доказательства дистрибутивности отличается от обозначенной тобой ранее
DG>во-вторых, с точки зрения математике, если, например, всё множество полем не является, то можно рассмотреть отдельные подмножества, которые являются полями, а потом на основе этого сделать вывод на основе всего множества.
Одно подмножество поле я вижу. Назови подмножество-поле, содержащее inf.
S>>Ты же написал что что-то не является объектом на всем множестве операций. Это не вопрос. Это утверждение. Т.е. ты не исследуешь эту ситуацию, для тебя это свершившийся факт. Но путем разбиения всего множества на какие-то части ты этот факт выворачиваешь. Вот это мне странно.
DG>при конструировании сложных вещей появляются куча элементов, которые почти такие же как исходные, но имеют какие-то добавочные свойства. при строгих выводах эти все добавочные элементы необходимо обозначать другими символами, но мне не хочется это делать на форуме из-за громоздкости.
Т.е. ты под символами (да и словами) подразумеваешь что-то свое, а другие на форуме об этом должны догадаться?
S>>Мне неизвестны формальные критерии принадлежности конкретной программы к ООП. Но известно что ты пока не смог предоставить непротиворечивую идентичность для того что бы рассматривать строки "с версионной иммутабельностью" и переменные как объекты.
DG>есть множество [строки, другие объекты]: DG>функция идентичности для данного множества DG> для [строка, строка] = equals(строка, строка) DG> для [строка, другой объект] = false DG> для [другой объект, другой объект] = referenceequals(другой объект, другой объект)
Такая функция идентичности не обсуждалась в этом топике. Вместо этого были определения об идентичности равнозначных строк + строк из "одной трассы операции сложения". Как я понял, именно те определения ты выдавал за идентичность с версионной иммутабельностью.
S>Одно подмножество поле я вижу. Назови подмножество-поле, содержащее inf.
скажи сколько полей тебе нужно.
вот тебе два поля:
возмем множество пар (kind,value) где каждая пара есть (c, комплексное-число) или (r, рациональное число)
с операциями + * следующего вида (обозначим операцию как op):
(c, c-number) op (с, c-number) = (c, c-number + c-number)
(r, r-number) op (r, r-number) = (r, r-number + r-number)
(c, c-number) op (r, r-number) = (r, r-number) op (c, c-number) = (c, c-number)
докажем, что операции + * дистрибутивны для всего множества:
дистрибутивность для троек вида(c, c-number) следует из того, что комплексные числа — поле
дистрибутивность для троек вида(r, r-number) следует из того, что рациональные числа — поле
дистрибутивность для оставшихся троек доказывается аналогично, как для предыдущего множества [числа;inf]
DG>>при конструировании сложных вещей появляются куча элементов, которые почти такие же как исходные, но имеют какие-то добавочные свойства. при строгих выводах эти все добавочные элементы необходимо обозначать другими символами, но мне не хочется это делать на форуме из-за громоздкости. S>Т.е. ты под символами (да и словами) подразумеваешь что-то свое, а другие на форуме об этом должны догадаться?
я опускаю очевидные выкладки, в частности то, что после каждого шага конструирования при котором были порождены Ex', которые есть Ex+свойства, происходит переопределение символов как: Ex = Ex'
S>>>Мне неизвестны формальные критерии принадлежности конкретной программы к ООП. Но известно что ты пока не смог предоставить непротиворечивую идентичность для того что бы рассматривать строки "с версионной иммутабельностью" и переменные как объекты.
DG>>есть множество [строки, другие объекты]: DG>>функция идентичности для данного множества DG>> для [строка, строка] = equals(строка, строка) DG>> для [строка, другой объект] = false DG>> для [другой объект, другой объект] = referenceequals(другой объект, другой объект)
S>Такая функция идентичности не обсуждалась в этом топике.
S>Схема доказательства дистрибутивности отличается от обозначенной тобой ранее
схема всё та же. при доказательстве рассматривается множество троек, а не просто множество исходных элементов.
соответственно из этого множества троек выделяются подмножества, которые дистрибутивны из-за того, что в них используются элементы из одного поля, а дальше остается рассмотреть только спец. тройки и доказать дистрибутивность для них каким-либо способом.
Здравствуйте, DarkGray, Вы писали:
S>>Одно подмножество поле я вижу. Назови подмножество-поле, содержащее inf.
DG>скажи сколько полей тебе нужно. DG>вот тебе два поля: DG>возмем множество пар (kind,value) где каждая пара есть (c, комплексное-число) или (r, рациональное число) DG>с операциями + * следующего вида (обозначим операцию как op):
вопрос снят, зачет.
DG>>>при конструировании сложных вещей появляются куча элементов, которые почти такие же как исходные, но имеют какие-то добавочные свойства. при строгих выводах эти все добавочные элементы необходимо обозначать другими символами, но мне не хочется это делать на форуме из-за громоздкости. S>>Т.е. ты под символами (да и словами) подразумеваешь что-то свое, а другие на форуме об этом должны догадаться?
DG>я опускаю очевидные выкладки, в частности то, что после каждого шага конструирования при котором были порождены Ex', которые есть Ex+свойства, происходит переопределение символов как: Ex = Ex'
И все выглядит так, будто ты что-то утверждаешь относительно исходного Ex. Подмена сивмолов не очевидная выкладка.
DG>>>есть множество [строки, другие объекты]: DG>>>функция идентичности для данного множества DG>>> для [строка, строка] = equals(строка, строка) DG>>> для [строка, другой объект] = false DG>>> для [другой объект, другой объект] = referenceequals(другой объект, другой объект)
S>>Такая функция идентичности не обсуждалась в этом топике.
DG>так такая функция тебя устраивает?
Такую я сам предлагал не далее чем осенью в этом форуме. Но я не делал сильных утверждений что только такой идентичностью можно достичь чего-то, что она имеет практический смысл.
S> Но я не делал сильных утверждений что только такой идентичностью можно достичь чего-то, что она имеет практический смысл.
такая формулировка означает, что есть какое-то смутное доп. требование к функции идентичности, выполнение которого необходимо для того, что функция идентичности имела смысл.
S>> Но известно что ты пока не смог предоставить непротиворечивую идентичность для того что бы рассматривать строки "с версионной иммутабельностью" и переменные как объекты.
есть множество [строки, другие объекты]:
функция идентичности для данного множества
для [строка, другой объект] = false
для [другой объект, другой объект] = referenceequals(другой объект, другой объект)
для [строка, строка] =
программа разбивается на отдельные кодовые операции, из кодовых операции выделяются подмножество кодовых типизированные операции вида строка op(строка, ..), для которых специфицировано, что op не меняет identity. для данных случаев считается, что строка на входе и строка на выходе это один и тот же объект (true). последовательность таких операций назовем трассой.
если два объекта не входят в одну трассу, то они считаются разными(false).
Здравствуйте, gandjustas, Вы писали:
V>>Тем не менее, для коммутативных операций это так. G>Тоже неверно. Представим коммутативную операцию a ~ b = b ~ a = 1. То есть всегда возвращающую одно значение. Для нее требуется вычислять аргументы? Вообще-то нет.
А как мы ее представим в SQL или РА?
G>Представим другую, некоммутативную операцию, a | b = not a. Для вычисления требуется вычислять аргументы? Тоже нет.
Ну.. сочинять несуществующие алгебры можно хоть до посинения. В любом случае, коль семантика операции известна (ты же настаиваешь, что вычислять аргументы не надо, т.е. мы знаем об этом), кто мешает привести ее к правой (канонической) части, и затем отбросить все эти рассуждения за ненадобностью?
G>Вообще если принять нормальный порядок вычислений, а не аппликативный, то порядок вычислений с порядком композиции почти никак не зависят друг от друга.
Это для независимых аргументов так. Дык, случай независимых аргументов априори не может вызвать разногласий, тут спорить нечего.
G>Так как нормальный порядок вычислений всегда дает результат если это возможно, то его можно принять за умолчание в любой выичслительной теории если явно не указано обратное. G>И в РА кажись не предполагается энергичный порядок.
Если у нас идут в выражении постоянные проекции и переименования, то даже для ленивого порядка вычислений необходимо будет сделать всю "линкову" всех проекций атрибутов и их переименований ДО начала вычислений, причем именно таким образом, как если бы эти значения распространялись в случае энергичного вычисления. Но и это не важно. Ленивость по природе своей не влияет на порядок вычислений атрибутов внутри кортежа, а влияет только на порядок получения всех кортежей относительно промежуточных результатов. Т.е. даже если кортежи вычисляются не все сразу, а по 1-му, всё равно ленивый порядок вычисления каждого атрибута кортежа будет соответствовать исходной формуле.
Здравствуйте, Sinclair, Вы писали:
V>>Уже показал на примере Cross production selection, где аналитический вид ф-ии ограничения считается известным, поэтому всё преобразование свелось к декомпозиции самой ф-ии ограничения и применения разных ее частей на разных этапах. Так вот, РА не занимается исследованием декомпозиций аналитических ф-ий, поэтому, хоть и показаны преобразования формул РА, это происходит не на уровне РА, а над ним. S>Ну то есть мы начинаем постепенно понимать, что оптимизатор запросов в СУБД работает не на уровне РА. Это хорошо.
Опять спор с самим собой. Речь была о том, применим ли аппарат РА на уровне таблицы, когда мы выбираем какой индекс можно использовать. Я утверждал, что применим, если рассматривать индексы как декомпозицию (а их так и рассматривают). Т.е. можно составить варианты исполнения в терминах РА и уже на этом уровне оценить затраты.
V>>Это как раз случай явной выразимости одних операций через другие, т.е. таких, где не требуется знание аналитического вида формул. S>Каких одних через какие другие?
Например, вариант 2 в твоей ссылке: последовательность операций ограничений можно выразить через одну операцию ограничения, соединив по AND критерии.
Вообще, спор насчет порядка операций — это малость в бок. Это невладение проблематикой. Я так нутром чую, что ты имел нечто вроде примера Selection and cross product, где если рассматривать формулу слева направо, то вроде как какие-то оптимизации есть... Однако возьми составлять некую формулу РА по заданному критерию результата, и у тебя сразу будет получаться формула в правой части. Потому что это естественно — применить предварительно ограничения к тому отношению, которое владеет требуемыми атрибутами, а уже к самой продукции применить лишь те ограничения, которые зависят одновременно от атрибутов исходных отношений.
Ноги нашего спора растут из-за различного понимания проблематики составления алгоритмов исполнения запросов. Уровень РА — это алгоритмический уровень, именно так запросы раскладывают на примитивные операции (я помню про твое добавления про 2 уровня планирования в MS SQL, по мне хоть 10, это итерации получения конечного решения). Ес-но, само РА — некий абстрактный уровень, бо вид конкретных контейнеров и способ реализации операций не оговаривается. Но сам аппарат предоставляет терминологию примитивных операций и даже кое-какие преобразования по ним. Почему я настаиваю, что РА как раз применим на уровне таблица->индексы. Потому что в классике проблематика стоит так: есть некий критерий результата, т.е. формула в терминах РИ, описывающая результат выборки из некоей схемы. Мы, зная ВСЮ декомпозицию схемы, составляем всевозможные варианты в терминах РА, которые удовлетворяют этому запросу. Вот на что натаскивают студентов по этим предметам. Однако, в реальных СУБД автоматически это невозможно, т.к. если у нас есть специальная избыточность и прикладные зависимости м/у атрибутами — то СУБД об этом никак не в курсе, она понятия не имеет о соотношении исходной прикладной схемы и декомпозированной — в виде реальных таблиц. В этом смысле ей сложновато составить действительно все варианты, удовлетворяющие прикладному запросу, поэтому в SQL мы явно указываем таблицы, из которых происходит выборка. И единственный уровень, который ей доступен — это декомпозиция таблиц и их индексов. Вот здесь уже можно составить ВСЕ варианты в терминах РА (или расширенной РА) вокруг одной таблицы и её индексов, провести оптимизацию (коль используются не внешние ф-ии, а ограничения, заданные в аналитическом виде в запросе) и затем применить оценку сложности каждого из вариантов, исходя из вида доступа, физического размера данных, статистики по индексам и т.д.
Выражения реляционной алгебры строятся на основе алгебраических операций (высокого уровня), и подобно тому, как интерпретируются арифметические и логические выражения, выражение реляционной алгебры также имеет процедурную интерпретацию. Другими словами, запрос, представленный на языке реляционной алгебры, может быть вычислен на основе вычисления элементарных алгебраических операций с учетом их старшинства и возможного наличия скобок. Для формулы реляционного исчисления однозначная интерпретация, вообще говоря, отсутствует. Формула только устанавливает условия, которым должны удовлетворять кортежи результирующего отношения. Поэтому языки реляционного исчисления являются более непроцедурными или декларативными.
V>>К тому же, про этот случай сказал в предыдущем сообщении, и его физический смыл был раскрыт в следующих строчках по твоей же ссылке: V>> V>>Операция AND в условиях выборки коммутативна, поэтому да. Даи это было лишнее для аргументации. Ведь часть операций РА, которые являются теоретико-множественными, коммутативны сами по себе, поэтому можно было просто привести вот так еще в самом начале: V>>A AND (B AND C) = (A AND B) AND C. V>>A OR (B OR C) = (A OR B) OR C. V>>Где A,B,C — совместимые отношения. Сразу бы и отделили коммутативные от некоммутативных, чтобы не обобщать огульно. S>Вы путаете коммутативность с ассоциативностью.
Коль речь была про порядок вычислений, то и то и другое неплохой пример.
A AND (B AND C) = (B AND C) AND A
И вообще, мне сложно вспомнить операцию, которая коммутативна и не ассоциативна при этом, всегда считал, что из одного следует другое. Обратное явно неверно.
V>>Нет, не поэтому, а исключительно из-за коммутативности. Аналогично вычислениям над обычными числами даже в императивной программе, часть вычислений можно проводить в произвольном порядке, если речь идет о коммутативных равноприоритетных операцих. S>Вы ошибаетесь. Возьмём, к примеру, коммутативную операцию над обычными числами: S>
S>int i = GetA()*GetB();
S>
S>Если у GetA() или GetB() есть побочный эффект, то перестановка порядка вычислений запрещена. Несмотря на коммутативность умножения.
Я не ошибаюсь. В С/С++ компилятор имеет право сгенерить произвольный порядок вычисления твоей формулы, а за побочными эффектами пусть следит программист. Порядок вычисления аргументов задан только для операций: || , &&. Любопытно, C# гарантирует порядок вычисления аргументов операций и методов? Вроде тоже нет.
V>>РА не занимается семантикой, это делается на уровне РИ и реляционной модели. Т.е., чтобы провести все те преобразования формул РА, помимо заведомо коммутативных преобразований (т.е. безусловным образом выразимых через друг друга), S>Алиса, никогда не употребляй слова только за то, что они длинные и красивые. Погуглите определение термина "коммутативность".
Хм, уже потерял нить беседы? Сорри, оперативно отвечать не имею возможности...
Это было на твой же пример:
Он верен из-за коммутативности операции AND:
V>>Возможно, хотя может сделать его процедурным, если мы не используем первоклассные ф-ии, не? S>Не, не может.
Т.е. в отсутствии первоклассных ф-ий всё равно функциональный подход? Хорошо себя чувствуешь?
V>>А процедурный подход относится к императивному или нет? Мне таки интересно твое развернутое мнение. Таки машина Тьюринга описана как автомат с ленточной памятью. S>А частично рекурсивные функции — нет. Дальше что?
А уже можно составить SQL-выражение, эквивалентное частично-рекурсивной ф-ии?
Давай определимся с твоим высказыванием сначала, что мой пример не делает функциональный подход императивным. Я предупреждал, что тема иммутабельности — скользкая. Мне любопытны аргументы.
V>>Ну коль для кластерного индекса строится точно такое же дерево на уровне неличтовых страниц, то чем он отличается от некластерного, когда на странице будет всего одна запись? S>Тем, что для некластерного таки будет создана отдельная страница. Вы не стесняйтесь, читайте литературу.
Когда на странице одна запись, то вроде не важно. Кластерный индекс всегда будет указывать не на диапазон, а на одну запись, как и некластерный.
V>>Насчет порядка: если некая соединительная операция из 3-х (грубо) составляющий выполняется в 4 раза быстрее, что каждая в среднем стала выполняться быстрее в корень 3-й степени из 4. S>Простите, но зачем вы продолжаете это делать? Времена выполнения операции Join очень косвенно связаны с произведением кардинальностей аргументов. S>Например, merge join вообще выполняется как O(N+M).
Ну это если одна таблица хранится сортированной под внешнему ключу, а другая по первичному. А если это не так и обе сильно не влазят в память, то формула будет малость посложнее. А если происходит join по какой-либо формуле, которой нет в виде индекса, то ближе к O(N*M). (Интересно, умеет ли MS SQL решать уравнения, чтобы привести join по формуле к O(log(N) + log(M) + N + M)?)
V>>Для удобства в MS Access после проверки этого выражения проверь вот это: V>>SELECT (TRUE AND (5 > NULL)) IS NULL S>Ок, я понял. Ваш опыт, которым вы так гордитесь, получен в основном на настольной СУБД.
Ух, лихо. Т.е. движок базы данных и офисное приложение — это уже одно и то же?
Как ответный реверанс — я вижу ограниченность/замкнутость на MS SQL. А у себя не помню ни одного проекта, где бы делали только под MS SQL. Мимимум под 3 базы обычно, где MS SQL — одна из них. Наиболее весело, когда одновременно под MS SQL и под Oracle.
V>>Это я про то, что порядок и вид выражений РА вовсе не обязан соответствовать "естественному" порядку исходного SQL. И еще про то, что SQL крайне избыточен, позволяя задавать одни и те же запросы очень многими способами. Так вот, из приведения всех вариантов запросов к одному (для данного случая) варианту в терминах РА следует, что вид операций РА слабо связан с видом выражения в SQL. S>Ок, хорошо, разница между РА и SQL становится всё более явной.
Дык, что разница есть — это говорилось. Так же как и то, что местами разницы нет. Например здесь: select * from X where X.x1 = 42. Для этого выражения есть только одно отображение в РА, поэтому и говорят, что в SQL присутствуют элементы РА, коль некоторые выражения будут взаимно-однозначны. Например на уровне РИ нет * from X, т.к. конкретная декомпозиция схемы не важна. Так же присутствуют элементы РИ, т.к. вид многих выражений задает не столько алгоритм запроса, сколько характеристики результата.
основной функцией манипуляционной части реляционной модели является обеспечение меры реляционности любого конкретного языка реляционных БД: язык называется реляционным, если он обладает не меньшей выразительностью и мощностью, чем реляционная алгебра или реляционное исчисление.
Не меньшей! А тебя смущает, что SQL обладает бОльшей выразительностью. Дык, пусть себе...
Конкретный язык манипулирования реляционными БД называется реляционно полным, если любой запрос, выражаемый с помощью одного выражения реляционной алгебры или одной формулы реляционного исчисления, может быть выражен с помощью одного оператора этого языка.
SQL реляционно-полон, разумеется. Любое выражение РА можно выразить через один оператор select (верхнего уровня).
V>>До сегодняшнего дня да, коль (x-y)==-(y-x). V>>Но у тебя ошибка в коде, нет учета переполнения. S>Воот. Эта ошибка связана с тем, что код предполагает такую же математику в компьютере, как и в учебнике. В учебнике у всех целых чисел есть их "антипод", -x = -1*x. S>А в компьютере — не у всех, разрядность ограничена. S>И можно действовать двумя способами: S>а) привести задачу к "условиям теории", чтобы можно было использовать весь теоретический аппарат S>б) привести решение к "специфике реализации", чтобы использовать тот аппарат, который есть на практике. S>В первом варианте мы начинаем требовать от компьютера поддержки целых чисел произвольной разрядности; во втором — подпиливаем код так, чтобы он корректно работал с учётом ограничений, несмотря на то, что он выглядит не как "теоретическое" решение. S>Вы пошли по второму варианту. S>Но для реляционной модели и SQL вы продолжаете настаивать на первом варианте.
Я понял рассуждения, но это рассуждения по аналогии. Например std::set прекрасно может обслужить задачи алгебры множеств в кач-ве контейнера, коль мн-ва будут заведомо конечны и влезут в память (пусть виртуальную). Т.е. я бы хотел таки услышать аргумент конкретно по РА. Бо в реальности мы тоже работаем с конечными мн-вами, и обратное не предполагается даже теорией РА, поэтому аналогия с конечностью разрядов малость хромает. Тем более, что все преобразования РА (по моему ИМХО) остаются валидны даже для повторяющихся записей, т.е. даже в случае некоторого выхода за реляционную модель.
ИМХО, уникальность записей нужна для уровня реляционного исчисления, которое оперирует отношениями и зависимостями м/у атрибутами, из-за этого дубликаты кортежей не имеют никакого физического смысла. Но уровень РА — это просто уровень операций над множествами, и на этом уровне физический смысл элементов этих множеств уже глубоко до фени. К тому же, сложно придумать такое представление кортежей в программе, чтобы экземпляры этих кортежей были неразличимы в адресации. А для использования наработок теории мн-в достаточно св-ва различимости элементов.
S>Мускул, простите, не показатель. В нём вообще много чего ещё нет. А встраиваемые и настольные базы данных я предлагаю не рассматривать — они не для промышленного применения, поэтому в них все новшества появляются с большим опозданием.
Когда речь идет о сценариях фактически read-only (крайне редкое обновление), и сами данные вменяемых размеров, то встраиваемые движки идут для "промышленного применения" аж бегом. Бо они резвые и эффективные в плане ресурсов. Это примерно как с микропроцессорами: на каждый центральный процессор компьютера есть около десятка суммарно в системнике и всей периферии, и еще больше в окружающих гаджетах... Сама MS использует движок Jet в нескольких приложениях для хранения реляционных данных (хотя файлы зачастую имеют другое расширение, не MDB), а в некоторых других использует MS SQL CE для тех же целей. Именно поэтому мы и делали задачи под разные СУБД, дабы давать возможность масштабирования. И плюс есть такая фишка — не все клиенты согласны на Windows + MS SQL, поэтому приходилось делать и под Oracle, и под остальное юниховое.
V>>Считается, что вокруг реляционных баз таки теория, а не просто инженерия. S>Да это-то я понимаю. Мне было интересно, что именно вы под этим словом понимаете. Потому что вы имеете трогательную привычку использовать термины неожиданным образом.
А при чем тут конкретно "теория реляционных субд"? Разве будет ошибкой относить сюда любые теоретические наработки вокруг СУБД? Характерно, что к ней относят даже языки РИ (коих несколько), которые, вообще-то, могут быть сугубо прикладными, если построить СУБД, удовлетворяющую правилам Кодда.
V>>Первично реализация требований. S>Ну вот видите. А теоретические модели — они появляются потом, когда мы анализируем решения, удовлетворяющие требованиям.
Дык, вся эта теория разрабатывалась в IBM для их DB, и была затем применена при разработке DB-2. Столько денег угрохать на исследования и не применять наработки? Я в это не поверю с т.з. здравого смысла. Да и какой смысл, изучая предмет реляционных СУБД отводить SQL пару последний занятий, зато мучить год реляционным исчислением и алгеброй?
S>>>И с дьявольской предусмотрительностью сделали основой модели SQL мультимножества для того, чтобы сразу же колбасить на SQL-совместимых СУБД постреляционные приложения и дать в полный рост развернуться системам ORM. V>>Для хранения объектов вообще реляционные субд не айс. Просто пользуют из-за надежной реализации транзакций... ИМХО, сугубо исторически. S>Конечно исторически. Просто кроме RDBMS на рынке ничего промышленно-надёжного так и не появилось. Успели выдавить в своё время.
Это я про то, что тема ORM в связке с реляционными СУБД теоретически неинтересна. Объектам не нужны ключи, две коллекции объектов одного типа не означают два разных прикладных отношения и т.д. до бесконечности. Про наследование вообще молчу, каждый извращается в меру своей распущенности. Надо смотреть на пост-реляционные. Попробуйте Postgre. Можно задавать пользовательские составные типы данных, хранить массивы в ячейках таблиц, есть непосредственный доступ к журналу, и прочие плюшки. Считается достаточно надежной, примерно в 10 раз надежней кода BSD.
V>>Неправильно, ты потерял контекст. S>Тогда напишите, как правильно. Когда именно лучше обыгрывать неуникальный ключ дополнительным отношением, вместо банального создания индекса? S>Первоначальная суть индексов — в уменьшении количества обращений к диску. S>Ограничение объёма данных — это один из способов добиться этого уменьшения, причём не самый эффективный.
V>>Есть еще фишка: по таблице кластерный индекс может быть только один, а такие "искусственные" индексы в виде отдельного отношения для прикладных сценариев могут иметь каждый свой кластерный индекс. S>Вы рассматривайте всю картину в целом. Сравните накладные расходы на неуникальный индекс и на "отдельное отношение" — даже если в этом отдельном отношении есть кластерный индекс.
Если неуникальный индекс некластерный, то все-равно в общем случае каждая запись будет доставаться из разных страниц. Сценарий уже был дан: это потребность в полях, помимо входящих в индекс. Тут рассматривать нечего: если записей этого "искусственного" индекса будет больше на каждой странице, то уже выигрыш на чтении есть. Вопрос, конечно, в том, насколько именно, тут зависит от физического размера искуственного индекса по отношению к размеру строки исходной таблицы и от кол-ва самих данных. Тут правильно делали замечание, что кеширование страниц со счетов сбрасывать не стоит, оно влияет оч. сильно на конечный результат. Ну и относительная частота записи-чтения играет роль, т.к. любой лишний индекс, даже искусственный — это лишняя нагрузка при обновлении.
Здравствуйте, vdimas, Вы писали:
V>Вообще, спор насчет порядка операций — это малость в бок. Это невладение проблематикой. Я так нутром чую, что ты имел нечто вроде примера Selection and cross product, где если рассматривать формулу слева направо, то вроде как какие-то оптимизации есть...
Я имел в виду то, что написал. И в жизни, и в теории реальный порядок вычисления промежуточных результатов весьма гибок.
V>Ноги нашего спора растут из-за различного понимания проблематики составления алгоритмов исполнения запросов.
Да.
V>
V>Выражения реляционной алгебры строятся на основе алгебраических операций (высокого уровня), и подобно тому, как интерпретируются арифметические и логические выражения, выражение реляционной алгебры также имеет процедурную интерпретацию. Другими словами, запрос, представленный на языке реляционной алгебры, может быть вычислен на основе вычисления элементарных алгебраических операций с учетом их старшинства и возможного наличия скобок. Для формулы реляционного исчисления однозначная интерпретация, вообще говоря, отсутствует. Формула только устанавливает условия, которым должны удовлетворять кортежи результирующего отношения. Поэтому языки реляционного исчисления являются более непроцедурными или декларативными.
Ну, это только одно из мнений. Я ссылку на другое приводил. Корни этого мнения понятны — выражение РА сразу подсказывает нам порядок вычисления "по умолчанию", из него легко построить императивный алгоритм. Это не означает, что этот императивный алгоритм — единственный.
V>И вообще, мне сложно вспомнить операцию, которая коммутативна и не ассоциативна при этом, всегда считал, что из одного следует другое. Обратное явно неверно.
Это да.
V>Я не ошибаюсь. В С/С++ компилятор имеет право сгенерить произвольный порядок вычисления твоей формулы, а за побочными эффектами пусть следит программист.
Ну и что? Это всего лишь означает, что С/С++ не следят за корректностью программы на таком уровне. А сама программа, очевидно, потеряет корректность при перестановке порядка вычислений только в случае наличия побочных эффектов. Коммутативность, ассоциативность, и приоритеты операций совершенно не важны.
Любопытно, C# гарантирует порядок вычисления аргументов операций и методов? Вроде тоже нет.
Вот как раз в C# всё хорошо: http://msdn.microsoft.com/en-us/library/Aa691322 http://msdn.microsoft.com/en-us/library/Aa691335
Но при этом у среды исполнения есть право переупорядочивания операций без побочных эффектов: http://msdn.microsoft.com/en-us/library/Aa691105
Обратите внимание, что само по себе это ничего не доказывает — есть разные языки. Алгоритмическая корректность никак не зависит от от того, что делается в реальном Паскале и разрешает ли С++ выстрелить себе в ногу.
V>Он верен из-за коммутативности операции AND: V>
А, ок.
V>>>Возможно, хотя может сделать его процедурным, если мы не используем первоклассные ф-ии, не? S>>Не, не может.
V>Т.е. в отсутствии первоклассных ф-ий всё равно функциональный подход? Хорошо себя чувствуешь?
V>>>А процедурный подход относится к императивному или нет? Мне таки интересно твое развернутое мнение. Таки машина Тьюринга описана как автомат с ленточной памятью. S>>А частично рекурсивные функции — нет. Дальше что?
V>А уже можно составить SQL-выражение, эквивалентное частично-рекурсивной ф-ии?
Всякое SQL-выражение эквивалентно некоторой частично-рекурсивной функции.
V>Давай определимся с твоим высказыванием сначала, что мой пример не делает функциональный подход императивным. Я предупреждал, что тема иммутабельности — скользкая. Мне любопытны аргументы.
Я потерял нить вашей мысли. Свою мысль я высказал — императивность начинается там, где есть состояние вычислителя, а с ним и возможность побочных эффектов. Декларативность начинается там, где кончаются побочные эффекты.
V>Когда на странице одна запись, то вроде не важно. Кластерный индекс всегда будет указывать не на диапазон, а на одну запись, как и некластерный.
Да.
V>>>Насчет порядка: если некая соединительная операция из 3-х (грубо) составляющий выполняется в 4 раза быстрее, что каждая в среднем стала выполняться быстрее в корень 3-й степени из 4. V>Ну это если одна таблица хранится сортированной под внешнему ключу, а другая по первичному.
Почему вы всё время скатываетесь на таблицы? Они участвуют только в примитивных запросах. В мало-мальски интересном случае аргументами операции являются не таблицы, а результаты других операций. V>А если это не так и обе сильно не влазят в память, то формула будет малость посложнее. А если происходит join по какой-либо формуле, которой нет в виде индекса, то ближе к O(N*M).
Это опять если они сильно не влазят в память. Это я к тому, что не стоит делать утверждения вроде выделенного — это так только в экстремальном частном случае.
(Интересно, умеет ли MS SQL решать уравнения, чтобы привести join по формуле к O(log(N) + log(M) + N + M)?)
Нет. Внутрь формул SQL не лезет (по крайней мере вплоть до 2005). Эффективность join можно убить насмерть написав on a.bID = b.id+0.
V>Ух, лихо. Т.е. движок базы данных и офисное приложение — это уже одно и то же?
Нет. Но аксессовый движок — для настольного применения.
V>Как ответный реверанс — я вижу ограниченность/замкнутость на MS SQL. А у себя не помню ни одного проекта, где бы делали только под MS SQL. Мимимум под 3 базы обычно, где MS SQL — одна из них. Наиболее весело, когда одновременно под MS SQL и под Oracle.
Большая тройка — это MS SQL, Oracle, DB2. Их легко найти в результатах TPC-C.
V>Дык, что разница есть — это говорилось. Так же как и то, что местами разницы нет. Например здесь: select * from X where X.x1 = 42. Для этого выражения есть только одно отображение в РА, поэтому и говорят, что в SQL присутствуют элементы РА, коль некоторые выражения будут взаимно-однозначны.
Ну так я о том, чтобы подчеркнуть — даже в этом случае выражение не сведётся к одной сигме в РА, хотя на первый взгляд это так.
V>Не меньшей! А тебя смущает, что SQL обладает бОльшей выразительностью. Дык, пусть себе...
Меня смущает только перспектива склеить РА, РИ, и SQL в голове программиста в одно понятие.
V>Я понял рассуждения, но это рассуждения по аналогии. Например std::set прекрасно может обслужить задачи алгебры множеств в кач-ве контейнера, коль мн-ва будут заведомо конечны и влезут в память (пусть виртуальную). Т.е. я бы хотел таки услышать аргумент конкретно по РА. Бо в реальности мы тоже работаем с конечными мн-вами, и обратное не предполагается даже теорией РА, поэтому аналогия с конечностью разрядов малость хромает.
Речь не о конечности чего-то, а о том, что математическая модель отличается от компьютерной.
V>Когда речь идет о сценариях фактически read-only (крайне редкое обновление), и сами данные вменяемых размеров, то встраиваемые движки идут для "промышленного применения" аж бегом. Бо они резвые и эффективные в плане ресурсов. Это примерно как с микропроцессорами: на каждый центральный процессор компьютера есть около десятка суммарно в системнике и всей периферии, и еще больше в окружающих гаджетах... Сама MS использует движок Jet в нескольких приложениях для хранения реляционных данных (хотя файлы зачастую имеют другое расширение, не MDB),
Это вы, наверное, про какой-то другой Jet. Вы же в курсе, что их два, да?
V>а в некоторых других использует MS SQL CE для тех же целей. Именно поэтому мы и делали задачи под разные СУБД, дабы давать возможность масштабирования. И плюс есть такая фишка — не все клиенты согласны на Windows + MS SQL, поэтому приходилось делать и под Oracle, и под остальное юниховое.
Ну вот наш продукт сейчас работает на MS SQL и PostreSQL
V>Если неуникальный индекс некластерный, то все-равно в общем случае каждая запись будет доставаться из разных страниц. Сценарий уже был дан: это потребность в полях, помимо входящих в индекс. Тут рассматривать нечего: если записей этого "искусственного" индекса будет больше на каждой странице, то уже выигрыш на чтении есть. Вопрос, конечно, в том, насколько именно, тут зависит от физического размера искуственного индекса по отношению к размеру строки исходной таблицы и от кол-ва самих данных. Тут правильно делали замечание, что кеширование страниц со счетов сбрасывать не стоит, оно влияет оч. сильно на конечный результат. Ну и относительная частота записи-чтения играет роль, т.к. любой лишний индекс, даже искусственный — это лишняя нагрузка при обновлении.
Ничего не понял. Где сравнение расходов на неуникальный некластерный индекс и расходов на внешнее отношение, играющее роль такого индекса?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>> Но я не делал сильных утверждений что только такой идентичностью можно достичь чего-то, что она имеет практический смысл.
DG>такая формулировка означает, что есть какое-то смутное доп. требование к функции идентичности, выполнение которого необходимо для того, что функция идентичности имела смысл.
DG>озвучь это требование
Единственное требование идентичности — различать объекты. Я утвеждал что ее можно немного ослабить в случаях когда объекты с различной идентичностью ECMA неотличимы по поведению.
Здравствуйте, DarkGray, Вы писали:
S>>> Но известно что ты пока не смог предоставить непротиворечивую идентичность для того что бы рассматривать строки "с версионной иммутабельностью" и переменные как объекты.
DG> для [строка, строка] = DG> программа разбивается на отдельные кодовые операции, из кодовых операции выделяются подмножество кодовых типизированные операции вида строка op(строка, ..), для которых специфицировано, что op не меняет identity. для данных случаев считается, что строка на входе и строка на выходе это один и тот же объект (true). последовательность таких операций назовем трассой. DG>если два объекта не входят в одну трассу, то они считаются разными(false).
А если входят, то ты должен уметь различать их по определению идентичности.
Здравствуйте, DarkGray, Вы писали:
S>>А если входят, то ты должен уметь различать их по определению идентичности.
DG>кому должен? DG>и как можно отличать строки внутри трассы по идентичности, если в данном случае утверждается что внутри одной трассы строки индентичны?
var empty = "";
var s1 = "1";
Это ведь разные объекты?
var emptyPlus1 = empty + s1;
А теперь empty и s1 разные? Или теперь они стали одним объектом? Если стали одним, куда делись empty и s1?
Я вижу, что ты трактуешь определение идентичности как "существуют как минимум два объекта и момент времени t, в который идентичность позволяет их отличить". Так это лично твои тараканы, которые не имеют отношения к ООП. Хочешь — назови это "конструктивным ООП".
Здравствуйте, gandjustas, Вы писали:
V>>>>Тем не менее, для коммутативных операций это так. G>>>Тоже неверно. Представим коммутативную операцию a ~ b = b ~ a = 1. То есть всегда возвращающую одно значение. Для нее требуется вычислять аргументы? Вообще-то нет.
V>>А как мы ее представим в SQL или РА? G>Функция, которая всегда возвращает пустую реляцию.
Я таки настаиваю ее изобразить. Потому что если это именно ф-ия как "черный ящик", то аргументы будут для такой ф-ии вычислены, хоть и не будут использованы внутри самой ф-ии, а если не черный ящик, то таки хотелось посмотреть на примере SQL (откуда она пойдет в РА).
G>>>Представим другую, некоммутативную операцию, a | b = not a. Для вычисления требуется вычислять аргументы? Тоже нет.
V>>Ну.. сочинять несуществующие алгебры можно хоть до посинения. G>Тем не менее такое можно выразить в терминах РА.
Нельзя.
V>>В любом случае, коль семантика операции известна (ты же настаиваешь, что вычислять аргументы не надо, т.е. мы знаем об этом), кто мешает привести ее к правой (канонической) части, и затем отбросить все эти рассуждения за ненадобностью? G>Так именно знание семантики позволяет проводить преобразования без вычисления. Ты же делаешь утверждения касающиеся всех коммутативных функций и говоришь что для них порядок вычислений связан с порядком композиции.
Речь о коммутативных операциях, а они даны были по ссылке. В остальном рассуждения такие же как для предыдущего примера, т.е. ты изобрел не операцию РА, а просто некую ф-ию и спекулируешь на порядке вычисления ее аргументов. Ты еще не забыл, ф-ии в РА применимы к каждому кортежу, а не ко всему отношению?
G>>>Вообще если принять нормальный порядок вычислений, а не аппликативный, то порядок вычислений с порядком композиции почти никак не зависят друг от друга. V>>Это для независимых аргументов так. Дык, случай независимых аргументов априори не может вызвать разногласий, тут спорить нечего. G>Это для любых аргументов.
G>>>Так как нормальный порядок вычислений всегда дает результат если это возможно, то его можно принять за умолчание в любой выичслительной теории если явно не указано обратное. G>>>И в РА кажись не предполагается энергичный порядок.
V>>Если у нас идут в выражении постоянные проекции и переименования, то даже для ленивого порядка вычислений необходимо будет сделать всю "линкову" всех проекций атрибутов и их переименований ДО начала вычислений, причем именно таким образом, как если бы эти значения распространялись в случае энергичного вычисления. Но и это не важно. G>Именно это и важно, и в РА описано что и как можно переставлять и объединять. Ты же говоришь что это сделать нельзя для некоторого класса преобразований.
Да, именно. Утверждал что перестановку в общем случае проводить нельзя. Можно только для случаев, являющихся заведомо коммутативными. Для всех остальных это будут преобразования, с получением совсем других выражений, что совсем не есть тоже самое, что перестановка. Это уже пошло жонглирование и уловки. К тому же, большинство преобразований имеют ограничения применимости, т.е. про общий случай говорить не приходится. Понятное дело, что коль с самого начала утверждалось о "вариантах" формул РА, то таки на каждый запрос РИ может быть несколько вариантов формул РА. Но вот получены ли они перестановкой порядка операций — это большой вопрос ни о чем.
Здравствуйте, Sinclair, Вы писали:
V>>А уже можно составить SQL-выражение, эквивалентное частично-рекурсивной ф-ии? S>Всякое SQL-выражение эквивалентно некоторой частично-рекурсивной функции.
Меня интересует та, которая имеет некий N, делающую ее невычислимой, простейший пример — бесконечная безусловная рекурсия (т.е. N=0). Как это выразить на SQL для любого удобного тебе N в рамках одного выражения?
V>>Давай определимся с твоим высказыванием сначала, что мой пример не делает функциональный подход императивным. Я предупреждал, что тема иммутабельности — скользкая. Мне любопытны аргументы. S>Я потерял нить вашей мысли. Свою мысль я высказал — императивность начинается там, где есть состояние вычислителя, а с ним и возможность побочных эффектов. Декларативность начинается там, где кончаются побочные эффекты.
Не так, ты упомянул функциональный. А инициализацию переменных я не могу считать за декларативность, сорри.
V>>>>Насчет порядка: если некая соединительная операция из 3-х (грубо) составляющий выполняется в 4 раза быстрее, что каждая в среднем стала выполняться быстрее в корень 3-й степени из 4. V>>Ну это если одна таблица хранится сортированной под внешнему ключу, а другая по первичному. S>Почему вы всё время скатываетесь на таблицы? Они участвуют только в примитивных запросах. В мало-мальски интересном случае аргументами операции являются не таблицы, а результаты других операций.
С результатами других операций все еще хуже, бо они получены в порядке индекса одного из исходных вариантов и могут не быть сортированы по отношению к требуемой следующей соединительной операции.
V>>А если это не так и обе сильно не влазят в память, то формула будет малость посложнее. А если происходит join по какой-либо формуле, которой нет в виде индекса, то ближе к O(N*M). S>Это опять если они сильно не влазят в память. Это я к тому, что не стоит делать утверждения вроде выделенного — это так только в экстремальном частном случае.
Это в случае для которого реляционная модель и разработана: для случая внешних хранилищ, на порядки больших размера ОП. Для данных, целиком помещающихся в ОП, реляционная модель не самый лучший вариант, гораздо эффективнее пространственные графы с непосредственными/физическими связями структур, а не ассоциативные связи реляционной модели.
S>(Интересно, умеет ли MS SQL решать уравнения, чтобы привести join по формуле к O(log(N) + log(M) + N + M)?) S>Нет. Внутрь формул SQL не лезет (по крайней мере вплоть до 2005). Эффективность join можно убить насмерть написав on a.bID = b.id+0.
V>>Ух, лихо. Т.е. движок базы данных и офисное приложение — это уже одно и то же? S>Нет. Но аксессовый движок — для настольного применения.
А десяток человек, работающих с неким сервером приложений, использующий in-proc движок — это настольное применение?
V>>Как ответный реверанс — я вижу ограниченность/замкнутость на MS SQL. А у себя не помню ни одного проекта, где бы делали только под MS SQL. Мимимум под 3 базы обычно, где MS SQL — одна из них. Наиболее весело, когда одновременно под MS SQL и под Oracle. S>Большая тройка — это MS SQL, Oracle, DB2. Их легко найти в результатах TPC-C.
Мы ищем у клиентов, а не у TPC.
V>>Дык, что разница есть — это говорилось. Так же как и то, что местами разницы нет. Например здесь: select * from X where X.x1 = 42. Для этого выражения есть только одно отображение в РА, поэтому и говорят, что в SQL присутствуют элементы РА, коль некоторые выражения будут взаимно-однозначны. S>Ну так я о том, чтобы подчеркнуть — даже в этом случае выражение не сведётся к одной сигме в РА, хотя на первый взгляд это так.
Если рассматривать X как неделимое целое — то сведется. Если же ты имел наличие индексов по X.x1, то можно начинать рассуждать о выборке над схемой (подсхемой?) X с учетом всей декомпозиции. Но только это уже не уровень SQL.
V>>Не меньшей! А тебя смущает, что SQL обладает бОльшей выразительностью. Дык, пусть себе... S>Меня смущает только перспектива склеить РА, РИ, и SQL в голове программиста в одно понятие.
Ах вон оно что... А чего же не боишься склеивания замыканий и циклов for в голове программиста в одно понятие (C)? Тоже ведь разные парадигмы внутри одного языка.
V>>Я понял рассуждения, но это рассуждения по аналогии. Например std::set прекрасно может обслужить задачи алгебры множеств в кач-ве контейнера, коль мн-ва будут заведомо конечны и влезут в память (пусть виртуальную). Т.е. я бы хотел таки услышать аргумент конкретно по РА. Бо в реальности мы тоже работаем с конечными мн-вами, и обратное не предполагается даже теорией РА, поэтому аналогия с конечностью разрядов малость хромает. S>Речь не о конечности чего-то, а о том, что математическая модель отличается от компьютерной.
Мм... но это хождение по кругу, делать утверждения, которые неспоримы т.е. банальны. Меня интересовали побочные эффекты конкретных перечисленных несоответствий. Вот я, как инженер, при решении использовать такую-то модель или нет ищу соответствия и несоответствия. Причем в виде конкретного списка и анализа каждого пункта этого списка, а не в виде абстрактного посыла, что "реализация может отличаться от модели". Конечно может... Что же теперь, изобретать велосипеды каждый раз?
V>>Когда речь идет о сценариях фактически read-only (крайне редкое обновление), и сами данные вменяемых размеров, то встраиваемые движки идут для "промышленного применения" аж бегом. Бо они резвые и эффективные в плане ресурсов. Это примерно как с микропроцессорами: на каждый центральный процессор компьютера есть около десятка суммарно в системнике и всей периферии, и еще больше в окружающих гаджетах... Сама MS использует движок Jet в нескольких приложениях для хранения реляционных данных (хотя файлы зачастую имеют другое расширение, не MDB), S>Это вы, наверное, про какой-то другой Jet. Вы же в курсе, что их два, да?
Я про тот, что используется для файлов формата MDB. Встречал иногда некие системные файлы в этом формате, которые прекрасно можно посмотреть после переименования. И где-то в офисных приложениях тоже натыкался на использование этого формата но под другим расширениемм файла.
Насчет 2 — не знаю... Я знаю 5 уровней драйверов: OLEDB, DAO, ADO, RDO, ODBC. Инсталляция MDAC ставила их все. Самые эффективные для Jet — это OLEDB и DAO. ADO — порой тормоз, но имеет кое-какие плюшки. RDO тоже имеет кое-какие уникальные операции, ради которых на однократных операциях юзают и его.
V>>а в некоторых других использует MS SQL CE для тех же целей. Именно поэтому мы и делали задачи под разные СУБД, дабы давать возможность масштабирования. И плюс есть такая фишка — не все клиенты согласны на Windows + MS SQL, поэтому приходилось делать и под Oracle, и под остальное юниховое. S>Ну вот наш продукт сейчас работает на MS SQL и PostreSQL
Отличный пример. Т.е. или таки у вас будет приличная разница в кодовой базе, или вы не особо сможете упражняться в TSQL и PL/PgSQL, выжимая всё из конкретной СУБД. Бо отрицать огромную разницу этих диалектов бессмысленно. Не говоря уже о разных типах поддерживаемых данных этими СУБД и самой философии этих СУБД относительно данных.
V>>Если неуникальный индекс некластерный, то все-равно в общем случае каждая запись будет доставаться из разных страниц. Сценарий уже был дан: это потребность в полях, помимо входящих в индекс. Тут рассматривать нечего: если записей этого "искусственного" индекса будет больше на каждой странице, то уже выигрыш на чтении есть. Вопрос, конечно, в том, насколько именно, тут зависит от физического размера искуственного индекса по отношению к размеру строки исходной таблицы и от кол-ва самих данных. Тут правильно делали замечание, что кеширование страниц со счетов сбрасывать не стоит, оно влияет оч. сильно на конечный результат. Ну и относительная частота записи-чтения играет роль, т.к. любой лишний индекс, даже искусственный — это лишняя нагрузка при обновлении. S>Ничего не понял. Где сравнение расходов на неуникальный некластерный индекс и расходов на внешнее отношение, играющее роль такого индекса?
Здравствуйте, vdimas, Вы писали:
V>Меня интересует та, которая имеет некий N, делающую ее невычислимой, простейший пример — бесконечная безусловная рекурсия (т.е. N=0). Как это выразить на SQL для любого удобного тебе N в рамках одного выражения?
Никак. Но ведь и не любую программу машины Тьюринга можно представить в виде SQL.
Декларативность начинается там, где кончаются побочные эффекты. V>Не так, ты упомянул функциональный. А инициализацию переменных я не могу считать за декларативность, сорри.
Я же вам дважды уже сказал отстать от функционального.
V>С результатами других операций все еще хуже, бо они получены в порядке индекса одного из исходных вариантов и могут не быть сортированы по отношению к требуемой следующей соединительной операции.
А могут и быть.
V>Это в случае для которого реляционная модель и разработана: для случая внешних хранилищ, на порядки больших размера ОП.
Нет. Реляционная модель была разработана не для джойнов по "произвольной формуле". А джойны по значению атрибута отлично работают и для больших внешних хранилищ.
V>А десяток человек, работающих с неким сервером приложений, использующий in-proc движок — это настольное применение?
В общем-то да. Вот когда ваш сервер приложений справится с нагрузкой хотя бы на уровне последних строчек TPC-C, можно будет говорить о промышленном применении.
V>Мы ищем у клиентов, а не у TPC.
Тогда всех порвёт мускул, широко распространённый по причине бесплатности.
V>>>Дык, что разница есть — это говорилось. Так же как и то, что местами разницы нет. Например здесь: select * from X where X.x1 = 42. Для этого выражения есть только одно отображение в РА, поэтому и говорят, что в SQL присутствуют элементы РА, коль некоторые выражения будут взаимно-однозначны. S>>Ну так я о том, чтобы подчеркнуть — даже в этом случае выражение не сведётся к одной сигме в РА, хотя на первый взгляд это так.
V>Если рассматривать X как неделимое целое — то сведется.
Не сведётся. Мы же это только что обсудили, зачем снова начинать?
V>Ах вон оно что... А чего же не боишься склеивания замыканий и циклов for в голове программиста в одно понятие (C)? Тоже ведь разные парадигмы внутри одного языка.
Я боюсь склеивания замыканий и их реализации в шарпе в одно понятие. Склеивания понятия цикла и оператора for в шарпе в одно понятие. А склеивания замыкания и циклов в одно понятие не боюсь, как и не боюсь склеивания понятий "таблица" и "хранимая процедура" в SQL в одно понятие.
V>Мм... но это хождение по кругу, делать утверждения, которые неспоримы т.е. банальны.
Но вы же постоянно пытаетесь с ними спорить V>Меня интересовали побочные эффекты конкретных перечисленных несоответствий. Вот я, как инженер, при решении использовать такую-то модель или нет ищу соответствия и несоответствия. Причем в виде конкретного списка и анализа каждого пункта этого списка, а не в виде абстрактного посыла, что "реализация может отличаться от модели". Конечно может... Что же теперь, изобретать велосипеды каждый раз?
При чём тут велосипеды? Вы опять спорите не со мной? А по поводу соответствия и несоответствия — хрен вы, а не ищете. Мне вас в несоответствия приходится носом тыкать, и вы даже после этого ухитряетесь их не видеть.
И это несмотря на то, что скажем, список несоответствий между SQL и реляционной моделью представлен в статье в википедии.
Да, для начала неплохо бы усвоить абстрактный посыл о том, что "реализация может отличаться от модели". Это чтобы в каждой новой области не приходилось вам мучительно доказывать, что эти различия существуют. После этого можно начинать тренироваться искать эти несоответствия самостоятельно, а не дожидаясь, пока вам Синклер на форуме не начнёт две недели подряд ежедневно про эти различия рассказывать.
Сначала будет тяжело. Зато потом будет масса позитивных результатов: например, можно будет не нести чушь про то, что ограничение длины записи продиктовано поддержкой кластерных индексов, или что требования порядка вычисления аргументов как-то связано с коммутативностью оператора.
V>Насчет 2 — не знаю... Я знаю 5 уровней драйверов: OLEDB, DAO, ADO, RDO, ODBC. Инсталляция MDAC ставила их все. Самые эффективные для Jet — это OLEDB и DAO. ADO — порой тормоз, но имеет кое-какие плюшки. RDO тоже имеет кое-какие уникальные операции, ради которых на однократных операциях юзают и его.
Понятно. Просто есть два движка с одинаковым названием: Jet Blue и Jet Red. Внутри они принципиально разные.
S>>Ничего не понял. Где сравнение расходов на неуникальный некластерный индекс и расходов на внешнее отношение, играющее роль такого индекса?
V>Тебе расходы по чтению нужны или по обновлению
Хоть какие. Лучше оба вида
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, gandjustas, Вы писали:
V>>>>А как мы ее представим в SQL или РА? G>>>Функция, которая всегда возвращает пустую реляцию.
V>>Я таки настаиваю ее изобразить. Потому что если это именно ф-ия как "черный ящик", то аргументы будут для такой ф-ии вычислены, хоть и не будут использованы внутри самой ф-ии, а если не черный ящик, то таки хотелось посмотреть на примере SQL (откуда она пойдет в РА). G>SQL, в отличие от РА предполагает аппликативный порядок вычислений. Найдешь реализацию SQL где это не так — спокойно сделаю.
И где это ограничение явно указано?
Опять же, ты не забыл замечание про минимум 2 вида аналитических выражений в РА — это собственно выражения РА и выражения-ограничения в выборке или разновидностях соединений. Какой уровень ты имел ввиду?
G>Значит можно аналогичное. Сути не меняет.
Меняет. Ты же походя присвоил коммутативность некоей произвольной ф-ии, показав затем, что она нихрена не коммутативна из своего определения. Меня это улыбнуло, понятное дело, просто любопытно таки докопаться до всей цепочки рассуждений, которое могло ТАКОЕ породить.
V>>Речь о коммутативных операциях, а они даны были по ссылке. В остальном рассуждения такие же как для предыдущего примера, т.е. ты изобрел не операцию РА, а просто некую ф-ию и спекулируешь на порядке вычисления ее аргументов. Ты еще не забыл, ф-ии в РА применимы к каждому кортежу, а не ко всему отношению? G>А что мешает такую функцию представить как функцию отношения? Например t — отношение, s — органичение, f — функция. если рассмотреть композицию s(f(t)), то она не равна f(s(t)), но ведь никто не мешает построить ограничение s' такое что s(f(t)) = f(s'(t)), причем при некоторых условиях на для f получится s семантически эквивалентно s'. Причем эти условия элементарно можно проверить.
Мешает то, что ф-ии ограничения, где аргументами идут отношения — это уровень исчисления кортежей, но не уровень РА. Задача РА как раз преобразовать "структурные" формулы РИ в "плоские" операции РА, где ф-ии ограничения будут в терминах операций над атрибутами кортежей. Курить определение ограничения в РА.
Т.е. в терминах РА вот таких операций нет:
select * from X where X.x1 in (select y1 from Y)
Это будет эквивалент такой операции:
select X.* from X inner join Y on X.x1 = Y.y1
Что ближе к такой последовательности 3-х операций РА, являющихся решением обоих уравнений:
tmp1 = X x Y
tmp2 = ограничение(x1=y1) tmp1
result = проекция{x1, x2, .. xN} tmp2
Можно записать в виде одной формулы, не суть, все равно будет 3 примитивные операции РА в ней.
Попробуй кстате, "просто поменять вычисления местами" (С), мне любопытно. Замечания про ленивые vs энергичные я уже делал — ничего не меняется на уровне вычисления атрибутов кортежей.
G>При этом f(s'(t)) может вычисляться быстрее, чем s(f(t)). И конечно любой движок субд пытается по-максимуму такие преобразования делать.
Я это понимаю, и даже давал больше по этой теме, но ты невнимательно читал. Да, именно, уровень РА нужен для того, чтобы в его терминах породить ВСЕВОЗМОЖНЫЕ решения исходной формулы, потому что коль на уровне РА отсутствуют ф-ии над отношениями, т.е. отстуствует вложенность в ограничениях, т.е. отсутствует рекурсия формул, становится возможным произвести оценку сложности операций. Так вот, там, где некий автоматический движок, перечисляющий всевозможные решения в терминах РА знает об декомпозиции исходной схемы на отношения, он может не просто породить s'(t), он может породить s'(t'), где t' — другое отношение, но сохраняющее зависимости исходной схемы. Прочувствовал разницу?
G>Конечно движок субд опирается на семантику того что происходит и некоммутативность некоторых операций в общем случае ему не помеха.
Так вот, к большому пребольшому сожалению, движки СУБД не имеют понятия о семантике, т.к. обычно не реализовано одно из самых важных правил Кодда, позволяющее сохранять зависимости исходного прикладного отношения и проведенной конкретной декомпозиции. СУБД не делает никаких предположений относительно избыточности данных, принадлежащих одному домену и одному "логическому" атрибуту в рамках всей схемы.
V>>Да, именно. Утверждал что перестановку в общем случае проводить нельзя. Можно только для случаев, являющихся заведомо коммутативными. G>См выше. Некоммутативность не помеха перестановке вычислений. А если рассмотреть более общую картину, где могут быть сайд-эффекты, то и коммутативность не всегда дает возможность вычисления переставить.
Нету сайд-эффектов, а последовательность вычислений есть.
Понимаешь... злобные функциональщики малость лукавят. Ф-ий подход зиждется на процедурном, а тот не отрицает зависимость результата от порядка вычисления. Просто коль отсутствуют побочные эффекты, то аргументы ф-ий можно вычислять в произвольном порядке. Но это малость не то же самое, что зависимые вычисления делать в произвольном порядке. А я на этой зависимости настаивал изначально, мне случай независимых аргументов неинтересен, на то они и независимые.
V>>Для всех остальных это будут преобразования, с получением совсем других выражений, что совсем не есть тоже самое, что перестановка. G>Это будет перестановка вычислений. Просто у тебя в мозгу засело что "порядок вычислений" == "порядок аргументов", что как раз не верно в большинстве случаев.
Знаешь ли, если формулы ДРУГИЕ, то они просто ДРУГИЕ. Не надо ничего изобретать. А для ДУРГИХ формул может быть коль угодно другой порядок вычислений. Разумеется, что все варианты выражений РА, эквивалентных одному РИ, приводимы друг к другу. Но я утверждал, что это в общем случае не возможно на уровне РА, только через уровень РИ, т.е. через подстановку отношений, управляемую зависимостями конкретной схемы. Мы же, на самом деле, не рассмотрели целый большой класс преобразований, который делается НАД РА. А спор вообще возник вокруг случая применения РА уже на уровне выбора — какие индексы для сканирования таблицы использовать при составлении "физического плана запроса". Я наоборот вижу, что как раз здесь весь аппарат реляционной теории и может разгуляться, ведь у базы есть вся информация о декомпозиции таблицы и ее индексов.
V>>Это уже пошло жонглирование и уловки. G>Это правда жизни. Большинство оптимизации так выполняется.
Не совсем так. Я уже пояснял каждый пример, где речь действительно идет об оптимизации. Например, повторные ограничения никто не делает, они объдиняются по AND ф-ий ограничений. но это происходит еще до РА, еще во время автоматической генерации алгоритма запроса. По крайней мере в решениях задач мы всегда поступали так же. Это естественно как таблица умножения, как вывод аналитического вида результата перед вычислением ответа-числа в задачах по физике. Тоже самое относительно "оптимизации" продукций: сразу в РА получается правая часть. Поэтому основная нагрузка при оптимизации малость не на этом, а на том, чтобы породить всевозможные варианты (уже минимизированные, понятно) операций в примитивных терминах и оценить сложность каждой из них и затем всего алгоритма (коль он состоит из примитивных операций) из статистики, кол-ва данных, вида организации данных (упорядоченное или неупорядоченное размещение) и т.д.
S>А теперь empty и s1 разные? Или теперь они стали одним объектом? Если стали одним, куда делись empty и s1?
не определено.
у функции + есть два варианта: string = string + string-diff, и new-string = string1 + string2.
первый случай сохраняет идентити, второй — нет.
в .net оба типа string и string-diff выражаются одним типом System.String, поэтому выбор правильного варианта:
или выбирается автоматически на основе ряда соглашений (в частности на основе имен переменных),
или явно указывается при вызове.
S>Я вижу, что ты трактуешь определение идентичности как "существуют как минимум два объекта и момент времени t, в который идентичность позволяет их отличить". Так это лично твои тараканы, которые не имеют отношения к ООП. Хочешь — назови это "конструктивным ООП".
я предлагаю использовать понятие идентичности через способ конструирования, потому что это конструктивно
при таком подходе:
1. сначала всё что есть(весь мир) делится на элементы.
2. потом из элементов выделяются элементы, которые являются гранями одного и того же объекта, а остальные элементы считаются различными объектами
в ряде случаев, процесс 1 может быть итерационный
вместо пары терминов элементы/объекты также может использоваться пара терминов — объекты/идентичные объекты.
пример использования такого подхода:
сначала выделили ссылки (выделили элементы), потом ссылки через reference-equals проверили, что они являются одним и тем же объектом
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, vdimas, Вы писали:
V>>Меня интересует та, которая имеет некий N, делающую ее невычислимой, простейший пример — бесконечная безусловная рекурсия (т.е. N=0). Как это выразить на SQL для любого удобного тебе N в рамках одного выражения? S>Никак. Но ведь и не любую программу машины Тьюринга можно представить в виде SQL.
S>Декларативность начинается там, где кончаются побочные эффекты.
ЧТД. Наконец ты сознался. Не верно. Декларативность — это относительное понятие, ортогональное к побочным эффектам. Если есть неких два уровня абстракции, то один из них декларативен к другому, если примитивы более высокоуровневой абстракции выражаются в терминах операций над примитивами более низкоуровневой. Но! Эта более низкоуровневая абстракция, в свою очередь, может являться декларативной по отношению к следующей низлежащей абстракции (или некоего реального воплощения).
В рассматриваемом вопросе побочные эффекты отсутствуют потому что мы рассматривали выборку. А когда рассматривается обновление в реляционной теории, то считается, что мн-во кортежей для обновления и данные для обновления вычислены ДО операции обновления. Т.е. подразумевается некая точка в которой вычисления должны стать энергичными, предвычисленными. Т.е. даже если у нас ленивость внизу, она должна обеспечивать эту семантику. поэтому побочные эффекты есть, так как и правила их обслуживания.
V>>С результатами других операций все еще хуже, бо они получены в порядке индекса одного из исходных вариантов и могут не быть сортированы по отношению к требуемой следующей соединительной операции. S>А могут и быть.
Ну так вот тебе и умножение вместо сложения в том случае, где нет. Видел порой в плане запроса операцию сортировки промежуточных результатов перед join? А сложность алгоритмов внешней сортировки какова?
V>>Это в случае для которого реляционная модель и разработана: для случая внешних хранилищ, на порядки больших размера ОП. S>Нет. Реляционная модель была разработана не для джойнов по "произвольной формуле". А джойны по значению атрибута отлично работают и для больших внешних хранилищ.
Еще раз — только при упорядоченности внешнего ключа одной и основного ключа другой таблицы. Иначе как минимум по одной из этих таблиц будет произвольный доступ, т.е. количество чтений страниц будет стремиться к кол-ву записей, т.е. коэф К при формуле может случиться оч большой.
V>>А десяток человек, работающих с неким сервером приложений, использующий in-proc движок — это настольное применение? S>В общем-то да. Вот когда ваш сервер приложений справится с нагрузкой хотя бы на уровне последних строчек TPC-C, можно будет говорить о промышленном применении.
Ну речь-то шла о масштабировании. Это одна из первых причин делать кросс-СУБД проекты. Нафига десятку человек такое дорогостоящее решение? В тоже время, если надо — прыгайте на сервер без проблем. Ну и на самом деле, при размерах данных, подходящих под применение встроенных движков, эффективность получается порой выше твоих тестов TPC, именно поэтому in-proc базы так популярны. Особенно когда предварительную обработку осуществляет многопоточный сервер приложений на нейтивной платформе. Эта связка на своих задачах заруливает MySql, а тот на многих задачах легко заруливает MS SQL. Почитай полно обсуждений в вебе по эффективности. У меня тоже свой опыт... когда были пни-200, то нейтивный сервер, со складом-бухгалтерией, использующий DCOM для клиентов в одноранговой сети с низлежащей базой на JET просто летал как бабочка, а поставили выделенный MS SQL в кач-ве базы на втрое более мощный комп — и все стало гораздо печальнее минимум на год, пока еще вдвое характеристики компов не подросли. Это и спасло при росте базы, потому как пришлось уже делать меньше оперативный период, что не всегда удобно.
V>>Мы ищем у клиентов, а не у TPC. S>Тогда всех порвёт мускул, широко распространённый по причине бесплатности.
Вот именно! Но если использовать его как внешний процесс — порвет далеко не всех. Прямо на сегодня ОЧЕНЬ неплохо выглядит in-proc MS SQL Compact Edition. Просто бомба по эффективности с таким богатым SQL. Все-таки Jet имеет бедный диалект SQL, и эффективен далеко не во всех сценариях. Только нельзя этот MS SQL CE его юзать из дотнета — дотнетный парсер потока весь цимус убивает да еще содержит ошибки при парсинге стримов к блобам (я им рапортовал тот баг, вроде не исправили еще в 4-й версии).
V>>Если рассматривать X как неделимое целое — то сведется. S>Не сведётся. Мы же это только что обсудили, зачем снова начинать?
Затем, что ты лихо скачешь по уровням абстракций, думая, что эта скачка уже аргумент сам по себе. Дудки. На любом уровне есть свои задачи, доступные инструменту РА. Такова особенность понятия "абстракция".
V>>Ах вон оно что... А чего же не боишься склеивания замыканий и циклов for в голове программиста в одно понятие (C)? Тоже ведь разные парадигмы внутри одного языка. S>Я боюсь склеивания замыканий и их реализации в шарпе в одно понятие. Склеивания понятия цикла и оператора for в шарпе в одно понятие. А склеивания замыкания и циклов в одно понятие не боюсь, как и не боюсь склеивания понятий "таблица" и "хранимая процедура" в SQL в одно понятие.
Тогда твоя боязнь очень избирательна, на примере разницы логического и физического плана запроса. Ты взял, да и привязался к конкретной реализации конкретной СУБД.
Да и вообще, сия боязнь странная. Ведь о чем мы там изначально? Я считал, что надо знать хотя бы самые популярные техники исполнения абстракций, чтобы писать адекватные современной аппаратуре программы. Поэтому знания техник исполнения замыканий в используемом инструменте всяко на пользу. Особенно если это замыкания дотнета, приводимые тут же к делегатам. Ты же считаешь, что эти знания во вред по приписываемой оппонентам несуразной причине "монолитности в голове". Демагогия как она есть.
V>>Меня интересовали побочные эффекты конкретных перечисленных несоответствий. Вот я, как инженер, при решении использовать такую-то модель или нет ищу соответствия и несоответствия. Причем в виде конкретного списка и анализа каждого пункта этого списка, а не в виде абстрактного посыла, что "реализация может отличаться от модели". Конечно может... Что же теперь, изобретать велосипеды каждый раз? S>При чём тут велосипеды? Вы опять спорите не со мной? А по поводу соответствия и несоответствия — хрен вы, а не ищете. Мне вас в несоответствия приходится носом тыкать, и вы даже после этого ухитряетесь их не видеть.
Ты ткнул несоответствием в плане возможной неуникальности промежуточных и даже итоговых данных. Я попросил на уровне РА показать, что это приведет к невалидности формул и преобразований РА. Давай уж, назвался груздем — полезай в кузов.
S>И это несмотря на то, что скажем, список несоответствий между SQL и реляционной моделью представлен в статье в википедии.
Ооо, повтор старой шарманки. Мне ссылку на мой предыдущий пост давать или копипастой заниматься?
основной функцией манипуляционной части реляционной модели является обеспечение меры реляционности любого конкретного языка реляционных БД: язык называется реляционным, если он обладает не меньшей выразительностью и мощностью, чем реляционная алгебра или реляционное исчисление.
Не меньшей! А тебя смущает, что SQL обладает бОльшей выразительностью. Дык, пусть себе...
Давай уже ближе к телу. Обоснуй, как более широкие возможности SQL мешают использовать наработки более узкой модели? Я бы еще понял когда наоборот, возможностей не хватает, тогда мы бы говорили лишь о части покрытия возможностей, но тут же ровно наоборот. В общем, за гранью здравого смысла уже.
S>Да, для начала неплохо бы усвоить абстрактный посыл о том, что "реализация может отличаться от модели". Это чтобы в каждой новой области не приходилось вам мучительно доказывать, что эти различия существуют. После этого можно начинать тренироваться искать эти несоответствия самостоятельно, а не дожидаясь, пока вам Синклер на форуме не начнёт две недели подряд ежедневно про эти различия рассказывать.
Таки придется, иначе просто заумная балаболка. Реализация всегда отличается от модели, на то она и модель, я не понимаю, почему у тебя проблема конкретно в СУБД. Ведь обыгрывают переполнения целых чисел в программах? И даже ограничения по точности чисел в плавающей. Однако же не мешает пользоваться всем аппаратом математики в вычислениях. Точно так же показал обыгрывание несчастного null. Неужели это и было предметом всего спора?
Понимаешь, твое отрицание применимости инструментов теории реляционных БД к реально существующим СУБД — это один из самых вредительских советов, который я тут видел за последнее время. Что-то вроде призывов к инженерному идиотизму. Поэтому таки я готов рассмотреть и показать обыгрывание отличий модели от реализации для всего твоего списка несоответствия. Попунктно.
S>Сначала будет тяжело. Зато потом будет масса позитивных результатов: например, можно будет не нести чушь про то, что ограничение длины записи продиктовано поддержкой кластерных индексов,
Улыбнуло, я думал ты уже понял, что тебе говорили.
Покажи-ка мне стоимость нахождения записи в случае кластерного индекса внутри страницы, если размер самой записи нефиксированный?
S>или что требования порядка вычисления аргументов как-то связано с коммутативностью оператора.
Э нет, аргументами для рассмотренного случая являются атрибуты и скалярные выражения, т.е. заведомо уже вычисленные вещи, а вот декомпозиция самих ограничений и возможность смены их порядка при повторных "накатываниях" ограничений действительно управляется коммутативностью операций составляющих аналитический вид ф-ии ограничения. Ты путаешь применение произвольной ф-ии к отношению (чего НЕТ в реляционной алгебре по определению, все операции над отношениями перечисленны), и собственно ф-ию ограничения, которая всегда над атрибутами.
V>>Насчет 2 — не знаю... Я знаю 5 уровней драйверов: OLEDB, DAO, ADO, RDO, ODBC. Инсталляция MDAC ставила их все. Самые эффективные для Jet — это OLEDB и DAO. ADO — порой тормоз, но имеет кое-какие плюшки. RDO тоже имеет кое-какие уникальные операции, ради которых на однократных операциях юзают и его. S>Понятно. Просто есть два движка с одинаковым названием: Jet Blue и Jet Red. Внутри они принципиально разные.
Ну, в VB тоже была своя встроенная ADO, так же была либа для С и ADO-обертка над ней в MFC.
То, что многие продукты MS используют формат MDB — это я за много лет видел невооруженным взглядом просто просматривая навскидку форматы их файлов. Но нам доступна только та, что устанавливалась раньше через MDAC, а сейчас через автообновления виндов, если создавать Engine через CreateObject. Хотя, надо ткнуть вот ту ESENT.DLL. Последние годы я за Jet не слежу, и ты дал интересную инфу, этот движок используется даже шире, чем я предполагал. А вот то, что забили на MS Access (это было понятно еще при переходе от 97-го офиса к 2000-му), — конечно жаль, похоже, это и породило новую ветку. Просто с офиса 2000 они стали продвигать MS Access больше как клиента к MS SQL, что сместило приоритеты. А зря. Нет ничего проще, чем породить в MS VC в визарде OLEDB интерфейс-провайдер к своему нейтивному серваку и прицепить MS Access как клиента — неимоверно эффективно и удобно, с учетом их потрясающего конструктора отчетов, в сравнении с полностью ручным GUI, каким-нить CORBA как протокол, и убогим Crystal Report. Я иногда использовал MS Access как внешнюю утилиту, вызываемую через автоматизацию, исключительно для формирования отчетов, бо оч удобно. (для не столь регуляных данных использовался MS Word точно так же): http://files.rsdn.ru/21096/ss1.PNG
S>>>Ничего не понял. Где сравнение расходов на неуникальный некластерный индекс и расходов на внешнее отношение, играющее роль такого индекса?
V>>Тебе расходы по чтению нужны или по обновлению S>Хоть какие. Лучше оба вида
Коль индекс неуникальный и мы договорились, что в отличие от основной таблицы этот индекс может быть кластерным, то по основной таблице для выборки M неуникальных записей по одному ключу из таблицы размером N понадобится O(log N)+O(M) чтений.
Для случая кластерного индекса по нашей искусственной избыточной таблицы порядок будет O(log N) — это время на поиск первого значения, остальные достаются за O(1) или даже за трудоемкость равную 0, т.к. преполагаются повторные чтения с той же страницы.
Для случая вставки в кластерный индекс всегда трудоемкость минимум O(n), помимо операции обновления дерева индекса, которая будет одинаковой стоимости что для исходной таблицы, что для избыточной. Но с этой сложностью борются, оставляя "зазоры" после удаления, чтобы свести ее ближе к логарифму.
S>>А теперь empty и s1 разные? Или теперь они стали одним объектом? Если стали одним, куда делись empty и s1?
DG>не определено.
Вот на этом и заканчивается разговор об ООП идентичности.
S>>Я вижу, что ты трактуешь определение идентичности как "существуют как минимум два объекта и момент времени t, в который идентичность позволяет их отличить". Так это лично твои тараканы, которые не имеют отношения к ООП. Хочешь — назови это "конструктивным ООП".
DG>я предлагаю использовать понятие идентичности через способ конструирования, потому что это конструктивно
Вот и предлагай, но это не ООП идентичность. DG>при таком подходе: DG>1. сначала всё что есть(весь мир) делится на элементы. DG>2. потом из элементов выделяются элементы, которые являются гранями одного и того же объекта, а остальные элементы считаются различными объектами DG>в ряде случаев, процесс 1 может быть итерационный DG>вместо пары терминов элементы/объекты также может использоваться пара терминов — объекты/идентичные объекты.
Я не вижу ничего конструктивного в этом подходе. Термин "идентичные объекты" уже использован в ООП. Выбери другой, что бы не вносить путаницу.
DG>пример использования такого подхода: DG>сначала выделили ссылки (выделили элементы), потом ссылки через reference-equals проверили, что они являются одним и тем же объектом
Если ссылка является объектом, то ты должен указать способ отличать ссылку-объект от объекта не ссылки.
DG>>не определено. S>Вот на этом и заканчивается разговор об ООП идентичности.
только для данного кода
DG>>я предлагаю использовать понятие идентичности через способ конструирования, потому что это конструктивно S>Вот и предлагай, но это не ООП идентичность.
определению удовлетворяет, а остальное это всё религия
DG>>вместо пары терминов элементы/объекты также может использоваться пара терминов — объекты/идентичные объекты. S>Я не вижу ничего конструктивного в этом подходе. Термин "идентичные объекты" уже использован в ООП. Выбери другой, что бы не вносить путаницу.
под определение "идентичные объекты" подходит, остальное — поиски еретиков.
DG>>пример использования такого подхода: DG>>сначала выделили ссылки (выделили элементы), потом ссылки через reference-equals проверили, что они являются одним и тем же объектом S>Если ссылка является объектом, то ты должен указать способ отличать ссылку-объект от объекта не ссылки.
нет, же конечно.
потому что с точки зрения данного построения, ни понятия ссылка-объект, ни понятия "объект не ссылка" — не существует.
DG>>пример использования такого подхода: DG>>сначала выделили ссылки (выделили элементы), потом ссылки через reference-equals проверили, что они являются одним и тем же объектом S>Если ссылка является объектом, то ты должен указать способ отличать ссылку-объект от объекта не ссылки.
вернемся к математике:
поверх булевой логике можно построить поле 1 со следующими правилами(допущениями):
операция + поля: xor
операция * поля: and
нулевой элемент поля: false
единичный элемент поля: true
поверх поля 1 можно построить поле 2 со следующими допущениями:
операция + поля: and
операция * поля: or
нулевой элемент поля: единичный элемент поля 1
единичный элемент поля: нулевой элемент поля 1
и в рамках таких построений бессмысленно требовать: чтобы операция * из поля 2 была согласована с нулем из поля 1.
при этом все выводы сделанные в рамках поля 2 справедливы для поля 1 и справедливы для самой булевой логике, пока эти выводы обратимы для использованных правил построения
соответственно:
если введено, что под объектом из построения 1 понимается ссылка из построения 0 на объект из построения 0, то бессмысленно требовать, чтобы был способ отличать "ссылку из построения 0 на объект из построения 1" от "объекта из построения 1 не ссылки из построения 0".
вообще, чтобы фраза "ты должен указать способ отличать ссылку-объект от объекта не ссылки" имела хоть какой-то смысл, для начала необходимо ввести, что такое ссылка в ООП вообще, и что такое ссылка в построении 1, при этом что такое ссылка в построении 0 было понятно, потому что использование понятие ссылка из .net-ных понятий, а не из понятий ООП.
DG>>>я предлагаю использовать понятие идентичности через способ конструирования, потому что это конструктивно S>>Вот и предлагай, но это не ООП идентичность.
DG>определению удовлетворяет, а остальное это всё религия
Не удовлетворяет.
S>>Я не вижу ничего конструктивного в этом подходе. Термин "идентичные объекты" уже использован в ООП. Выбери другой, что бы не вносить путаницу.
DG>под определение "идентичные объекты" подходит, остальное — поиски еретиков.
Не подходит.
DG>>>сначала выделили ссылки (выделили элементы), потом ссылки через reference-equals проверили, что они являются одним и тем же объектом S>>Если ссылка является объектом, то ты должен указать способ отличать ссылку-объект от объекта не ссылки.
DG>нет, же конечно. DG>потому что с точки зрения данного построения, ни понятия ссылка-объект, ни понятия "объект не ссылка" — не существует.
Ты что-то называешь ссылками, что-то называешь объектами, явно их различаешь, а потом утверждаешь косвенно что ссылки являются объектами. Ты уж определись, существуют ли они.
DG>>>пример использования такого подхода: DG>>>сначала выделили ссылки (выделили элементы), потом ссылки через reference-equals проверили, что они являются одним и тем же объектом S>>Если ссылка является объектом, то ты должен указать способ отличать ссылку-объект от объекта не ссылки.
DG>вернемся к математике: DG>поверх булевой логике можно построить поле 1 со следующими правилами(допущениями): DG>операция + поля: xor DG>операция * поля: and DG>нулевой элемент поля: false DG>единичный элемент поля: true DG>поверх поля 1 можно построить поле 2 со следующими допущениями: DG>операция + поля: and DG>операция * поля: or DG>нулевой элемент поля: единичный элемент поля 1 DG>единичный элемент поля: нулевой элемент поля 1
С математикой ты не дружишь. В "поле 2" нет нейтрального элемента для (+).
DG>и в рамках таких построений бессмысленно требовать: чтобы операция * из поля 2 была согласована с нулем из поля 1. DG>при этом все выводы сделанные в рамках поля 2 справедливы для поля 1 и справедливы для самой булевой логике, пока эти выводы обратимы для использованных правил построения
DG>соответственно: DG>если введено, что под объектом из построения 1 понимается ссылка из построения 0 на объект из построения 0, то бессмысленно требовать, чтобы был способ отличать "ссылку из построения 0 на объект из построения 1" от "объекта из построения 1 не ссылки из построения 0". DG>вообще, чтобы фраза "ты должен указать способ отличать ссылку-объект от объекта не ссылки" имела хоть какой-то смысл, для начала необходимо ввести, что такое ссылка в ООП вообще, и что такое ссылка в построении 1, при этом что такое ссылка в построении 0 было понятно, потому что использование понятие ссылка из .net-ных понятий, а не из понятий ООП.
А ты давал определение ссылки? Если нет, почему я не могу использовать понятие из .net? Ты ведь упоминаешь ссылки в своих тезисах...
DG>>вернемся к математике: DG>>поверх булевой логике можно построить поле 1 со следующими правилами(допущениями): DG>>операция + поля: xor DG>>операция * поля: and DG>>нулевой элемент поля: false DG>>единичный элемент поля: true DG>>поверх поля 1 можно построить поле 2 со следующими допущениями: DG>>операция + поля: and DG>>операция * поля: or DG>>нулевой элемент поля: единичный элемент поля 1 DG>>единичный элемент поля: нулевой элемент поля 1
S>С математикой ты не дружишь. В "поле 2" нет нейтрального элемента для (+).
не тормози.
true (он же единичный элемент поля 1) является нейтральным элементом для and с точки зрения операции +.
false(1) and(+) true(0) = false(1)
true(0) and(+) true(0) = true(0)
DG>>вообще, чтобы фраза "ты должен указать способ отличать ссылку-объект от объекта не ссылки" имела хоть какой-то смысл, для начала необходимо ввести, что такое ссылка в ООП вообще, и что такое ссылка в построении 1, при этом что такое ссылка в построении 0 было понятно, потому что использование понятие ссылка из .net-ных понятий, а не из понятий ООП. S>А ты давал определение ссылки?
в данном случае, я не обязан его давать. потому что внутри построения 1 я это понятие не использовал.
и я не видел определения, в котором было бы написано, что понятие "ссылка" требуется для ООП
S> Если нет, почему я не могу использовать понятие из .net? Ты ведь упоминаешь ссылки в своих тезисах...
использовать можешь, но напрямую в рамках построения 1 смысла оно уже не имеет.
вопрос может быть другим: во что переходит .net-ссылка из построения 0 при переходе в построение 1, и во что переходит объект не ссылка из построения 0 при переходе в построение 1?
DG>>не тормози. S>Да, с этим я тормознул.
S>А покажи мне существование обратного элемента для false относительно сложения (and) для поля 2. Напомню, что сложение с обратным элементом должно дать ноль, т.е. true.
множество (true, false) есть взаимно-однозначное отображение множества (false, true).
при этом операция or переходит в операцию and и наоборот.
дальше догадаешься, как выглядит алгоритм построения обратного элемента?
DG>>определению удовлетворяет, а остальное это всё религия S>Не удовлетворяет.
тому которое ты приводил — удовлетворяет, этому определению что угодно удовлетворяет.
DG>>под определение "идентичные объекты" подходит, остальное — поиски еретиков. S>Не подходит.
приведи логический вывод.
(хотя это может быть тяжело для человека, которые не понимает как связаны между собой операции and и or.)
DG>>нет, же конечно. DG>>потому что с точки зрения данного построения, ни понятия ссылка-объект, ни понятия "объект не ссылка" — не существует. S>Ты что-то называешь ссылками, что-то называешь объектами, явно их различаешь, а потом утверждаешь косвенно что ссылки являются объектами. Ты уж определись, существуют ли они.
в построении 0 существуют, в построении 1 — не существуют, пока не приведено конструктивного определения, что такое ссылка
Здравствуйте, vdimas, Вы писали:
V>ЧТД. Наконец ты сознался. Не верно. Декларативность — это относительное понятие, ортогональное к побочным эффектам. Если есть неких два уровня абстракции, то один из них декларативен к другому, если примитивы более высокоуровневой абстракции выражаются в терминах операций над примитивами более низкоуровневой.
Это определение — ваше личное изобретение. Оно не имеет никакого отношения к традиционной трактовке разницы между императивным и декларативным программированием.
Но это бы ничего, если бы определение имело хоть какой-то практический смысл. Но нет — не имеет. В частности, по вашему определению РА одновременно более декларативна чем РИ, и менее декларативна чем оно же, и мы возвращаемся к тому, с чего начали: РА и РИ одинаково декларативны.
V>>>С результатами других операций все еще хуже, бо они получены в порядке индекса одного из исходных вариантов и могут не быть сортированы по отношению к требуемой следующей соединительной операции. S>>А могут и быть. V>Ну так вот тебе и умножение вместо сложения в том случае, где нет. Видел порой в плане запроса операцию сортировки промежуточных результатов перед join? А сложность алгоритмов внешней сортировки какова?
Вы путаете общее с частным, делая всеобщее утверждение на основе некоторго частного случая.
S>>Нет. Реляционная модель была разработана не для джойнов по "произвольной формуле". А джойны по значению атрибута отлично работают и для больших внешних хранилищ. V>Еще раз — только при упорядоченности внешнего ключа одной и основного ключа другой таблицы.
Зачем вы продолжаете делать некорректные всеобщие утверждения? Очевидно, что для перехода от O(M*N) к O(M*log(N)) достаточно отсортированности только одного аргумента. И если мы говорим конкретно о таблицах и внешних ключах, как вы настаиваете, а не об общем случае табличных аргументов, то отсортированность — таки самый частый случай. Поэтому не надо думать, что ускорение вычисления каждого из аргументов на 50% даст вам 125% улучшения в скорости джойна.
V>У меня тоже свой опыт... когда были пни-200, то нейтивный сервер, со складом-бухгалтерией, использующий DCOM для клиентов в одноранговой сети с низлежащей базой на JET просто летал как бабочка, а поставили выделенный MS SQL в кач-ве базы на втрое более мощный комп — и все стало гораздо печальнее минимум на год, пока еще вдвое характеристики компов не подросли. Это и спасло при росте базы, потому как пришлось уже делать меньше оперативный период, что не всегда удобно.
Я ваш опыт обсуждать не буду. Не глядя в исходники невозможно сказать, движок ли виноват или плохо написанное приложение.
V>Тогда твоя боязнь очень избирательна, на примере разницы логического и физического плана запроса. Ты взял, да и привязался к конкретной реализации конкретной СУБД.
Я нигде не привязался к конкретной реализации. Разница между логическим и физическим планами есть везде, где есть оптимизатор запросов. Читайте литературу.
V>Да и вообще, сия боязнь странная. Ведь о чем мы там изначально? Я считал, что надо знать хотя бы самые популярные техники исполнения абстракций, чтобы писать адекватные современной аппаратуре программы. Поэтому знания техник исполнения замыканий в используемом инструменте всяко на пользу. Особенно если это замыкания дотнета, приводимые тут же к делегатам. Ты же считаешь, что эти знания во вред по приписываемой оппонентам несуразной причине "монолитности в голове". Демагогия как она есть.
Нет, я не считаю, что сами по себе знания во вред. Вред приносят заблуждения. Вы продолжаете их изрекать со скоростью 2-5 заблуждения за пост. И я вижу некоторую систему в отдельных заблуждениях. Как глядя на реку, я не вижу валунов, лежащих на дне; но по ряби на поверхности я могу делать выводы об их наличии и расположении.
Так же и здесь — глядя на форум, я не вижу валунов у вас в голове. Но они проявляются в виде ряби на поверхности — некорректных утверждений, которые вы делаете.
V>Ты ткнул несоответствием в плане возможной неуникальности промежуточных и даже итоговых данных. V>Давай уже ближе к телу. Обоснуй, как более широкие возможности SQL мешают использовать наработки более узкой модели?
ОМГ. Вы сейчас какое конкретно моё утверждение пытаетесь оспорить? Найдите его и процитируйте. Я понимаю, вам удобнее спорить с тезисом, которого я не высказывал. Но всё же постарайтесь держаться в рамках беседы.
V>Таки придется, иначе просто заумная балаболка. Реализация всегда отличается от модели, на то она и модель, я не понимаю, почему у тебя проблема конкретно в СУБД.
Да у меня-то нигде проблем нет. Я вам СУБД привёл как один только пример. Я не виноват, что вы полезли в дебри, в которых плохо разбираетесь. V>Ведь обыгрывают переполнения целых чисел в программах?
Да, я вам даже привёл пример на эту тему.
V>И даже ограничения по точности чисел в плавающей. Однако же не мешает пользоваться всем аппаратом математики в вычислениях.
Ну, таки мешает. Я вам даже пример привёл на эту тему. А уж в числах с плавающей запятой совсем копец: там аппаратом математики вещественных чисел пользоваться практически вовсе нельзя. Но давайте не будем ещё и в плавающую запятую лезть — у меня не хватит энергии на всё.
V>Улыбнуло, я думал ты уже понял, что тебе говорили. V>Покажи-ка мне стоимость нахождения записи в случае кластерного индекса внутри страницы, если размер самой записи нефиксированный?
Что вы называете "нахождением"? Указать, где начинается запись? Или прочесть некоторое поле F, не входящее в ключ индекса? Если второе — то стоимость в терминах логических чтений, очевидно, равна log(N, KeysPerPage)+ PagesPerRecord, где PagesPerRecord — количество страниц, занятых записью.
Встречный вопрос: а что, для некластерного индекса ситуация будет какой-то другой? И вообще, давайте так: вы прекратите намекать с умным видом, а просто напишете своими словами вид логической цепочки, которая приводит от утверждения "кластерный индекс — такой вид индекса, при котором значения ключей хранятся в самих данных, а порядок расположения данных определяется порядком значений ключа" к утверждению "размер записи таблицы, по которой строится кластерный индекс, должен быть меньше размера страницы".
И, кстати, выходные прошли. Что там у вас со смелым экспериментом по определению количества логических чтений в кластерных и некластерных индексах? Удалось получить разницу хотя бы в одну страницу?
V>Э нет, аргументами для рассмотренного случая являются атрибуты и скалярные выражения, т.е. заведомо уже вычисленные вещи, а вот декомпозиция самих ограничений и возможность смены их порядка при повторных "накатываниях" ограничений действительно управляется коммутативностью операций составляющих аналитический вид ф-ии ограничения. Ты путаешь применение произвольной ф-ии к отношению (чего НЕТ в реляционной алгебре по определению, все операции над отношениями перечисленны), и собственно ф-ию ограничения, которая всегда над атрибутами.
Я ничего не путаю. Я понимаю, что вы пытаетесь обосновать порядок вычисления аргументов одних операций (над отношениями) коммутативностью других (над атрибутами). Тем не менее принципиальным остаётся отсутствие побочных эффектов в запросах. Поэтому когда мы берём дерево реляционных операций, листья в нём могут вычисляться в любом порядке. Это даже если мы не рассматриваем все эти эквивалентности, которые позволяют нам ещё и перестраивать само дерево.
S>>Понятно. Просто есть два движка с одинаковым названием: Jet Blue и Jet Red. Внутри они принципиально разные. V>Ну, в VB тоже была своя встроенная ADO, так же была либа для С и ADO-обертка над ней в MFC.
Обёртки тут ни при чём. Я про engine. В MS Access использовался Jet Red. Jet Blue используется в Microsoft Exchange и Active Directory.
V>Коль индекс неуникальный и мы договорились, что в отличие от основной таблицы этот индекс может быть кластерным, то по основной таблице для выборки M неуникальных записей по одному ключу из таблицы размером N понадобится O(log N)+O(M) чтений. V>Для случая кластерного индекса по нашей искусственой избыточной таблицы порядок будет O(log N) — это время на поиск первого значения, остальные достаются за O(1) или даже за трудоемкость равную 0, т.к. преполагаются повторные чтения с той же страницы.
По-моему, вы хитрите. Вот у нас таблица T(A1..Ax, IK). В ней IK — это один или несколько атрибутов, входящих в ключ нашего неуникального индекса. A1..Ax — атрибуты, не входящие в ключ индекса.
Итак, поиск значений атрибутов A1..Ax по фиксированному значению ключа IK = IK1, занимает, как вы верно подметили, log(N) чтений для нахождения списка RID, и ещё M чтений для собственно доступа к записям (bookmark lookup).
Что именно вы собрались "обыгрывать" в дополнительной таблице T2? Вынести туда IK и ссылку на PK основной таблицы? Ну так для чтения атрибутов A1..Ax вы получите по-прежнему log(N) чтений на поиск значения, + log(N)+M чтений на доступ к основной таблице.
Если вы планируете включить в T2 что-то из A1..Ax, то их же можно включить в тот же неуникальный индекс и иметь те же преимущества доступа за log(N) без накладных расходов, связанных с поддержкой отдельной таблицы.
V>Для случая вставки в кластерный индекс всегда трудоемкость минимум O(n), помимо операции обновления дерева индекса, которая будет одинаковой стоимости что для исходной таблицы, что для избыточной. Но с этой сложностью борются, оставляя "зазоры" после удаления, чтобы свести ее ближе к логарифму.
Откуда вы взяли трудоёмкость вставки в O(N)? Стоимость всегда логарифмическая — это же дерево.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
V>Это будет эквивалент такой операции: V>select X.* from X inner join Y on X.x1 = Y.y1
V>Что ближе к такой последовательности 3-х операций РА, являющихся решением обоих уравнений: V>tmp1 = X x Y V>tmp2 = ограничение(x1=y1) tmp1 V>result = проекция{x1, x2, .. xN} tmp2 V>Можно записать в виде одной формулы, не суть, все равно будет 3 примитивные операции РА в ней.
Или две. Задача решается через переименование и полуджоин. Или через equi-джоин и проекцию. Но не суть.
Суть в том, что порядок вычисления X и Y не важен. Можно сначала рассчитать Y, а потом уже X. А можно — наоборот. Нам не важно, какие формулы стоят на местах X и Y, т.к. эти формулы заведомо не имеют побочных эффектов. Именно в этом суть декларативности РА.
V>Нету сайд-эффектов, а последовательность вычислений есть. V>Понимаешь... злобные функциональщики малость лукавят. Ф-ий подход зиждется на процедурном, а тот не отрицает зависимость результата от порядка вычисления. Просто коль отсутствуют побочные эффекты, то аргументы ф-ий можно вычислять в произвольном порядке. Но это малость не то же самое, что зависимые вычисления делать в произвольном порядке. А я на этой зависимости настаивал изначально, мне случай независимых аргументов неинтересен, на то они и независимые.
Вы делали всеобщее утверждение про фиксированность порядка вычислений в РА. Вам показали что нет, не всегда он фиксирован.
V>>>Для всех остальных это будут преобразования, с получением совсем других выражений, что совсем не есть тоже самое, что перестановка. G>>Это будет перестановка вычислений. Просто у тебя в мозгу засело что "порядок вычислений" == "порядок аргументов", что как раз не верно в большинстве случаев.
V>Знаешь ли, если формулы ДРУГИЕ, то они просто ДРУГИЕ. Не надо ничего изобретать. А для ДУРГИХ формул может быть коль угодно другой порядок вычислений. Разумеется, что все варианты выражений РА, эквивалентных одному РИ, приводимы друг к другу. Но я утверждал, что это в общем случае не возможно на уровне РА, только через уровень РИ, т.е. через подстановку отношений, управляемую зависимостями конкретной схемы. Мы же, на самом деле, не рассмотрели целый большой класс преобразований, который делается НАД РА. А спор вообще возник вокруг случая применения РА уже на уровне выбора — какие индексы для сканирования таблицы использовать при составлении "физического плана запроса". Я наоборот вижу, что как раз здесь весь аппарат реляционной теории и может разгуляться, ведь у базы есть вся информация о декомпозиции таблицы и ее индексов.
V>Не совсем так. Я уже пояснял каждый пример, где речь действительно идет об оптимизации. Например, повторные ограничения никто не делает, они объдиняются по AND ф-ий ограничений. но это происходит еще до РА, еще во время автоматической генерации алгоритма запроса.
В целом правильно, хотя и несколько наивно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>>определению удовлетворяет, а остальное это всё религия S>>Не удовлетворяет.
DG>тому которое ты приводил — удовлетворяет, этому определению что угодно удовлетворяет.
DG>>>под определение "идентичные объекты" подходит, остальное — поиски еретиков. S>>Не подходит.
DG>приведи логический вывод.
ты сам сказал, что идентичность может быть неопределена.
DG>(хотя это может быть тяжело для человека, которые не понимает как связаны между собой операции and и or.)
Это ты о том, что они не образуют группу?
DG>>>потому что с точки зрения данного построения, ни понятия ссылка-объект, ни понятия "объект не ссылка" — не существует. S>>Ты что-то называешь ссылками, что-то называешь объектами, явно их различаешь, а потом утверждаешь косвенно что ссылки являются объектами. Ты уж определись, существуют ли они.
DG>в построении 0 существуют, в построении 1 — не существуют, пока не приведено конструктивного определения, что такое ссылка
Но это не мешает тебе использовать термин для своего построения
S>>А покажи мне существование обратного элемента для false относительно сложения (and) для поля 2. Напомню, что сложение с обратным элементом должно дать ноль, т.е. true.
DG>на самом деле, я действительно не прав. извини. DG>or и and не образуют группу, хотя я почему-то считал обратное.
DG>зы DG>значит в построении 2 придется брать в качестве операции +: операцию эквивалентности
И что будет обратным элементом для false?
Здравствуйте, DarkGray, Вы писали:
DG>>>значит в построении 2 придется брать в качестве операции +: операцию эквивалентности S>>И что будет обратным элементом для false?
DG>false
Точно, эквивалентность же.
S>>С "полем 1" будем разбираться?
DG>а что с ним разбираться, если оно сейчас такое же как поле 2 с точностью до взаимно-однозначного отображения
Можешь указать обратный элемент для true на операции or?
DG>>приведи логический вывод. S>ты сам сказал, что идентичность может быть неопределена.
это лишь означает, что:
1. во-первых, для данного программы можно определить как хочется
2. во-вторых, что для данной программы такое построение делать не стоит, но из этого не следует, что его не стоит делать для произвольной программы
DG>>в построении 0 существуют, в построении 1 — не существуют, пока не приведено конструктивного определения, что такое ссылка S>Но это не мешает тебе использовать термин для своего построения
конечно. алгоритм построения 1 работает в терминах построения 0, поэтому он может использовать понятия из построения 0, но внутри построения 1 эти понятия уже становятся бессмысленными
как отдаленный пример:
(x+y)*(x+y) = x+y //построение 0
x*x = x //построение 1, построенное заменой переменной x = x+y
и в рамках построения 1 бессмысленно говорить, а чему же равен y? он там просто не определен.
мир -> построение -> мир 1
когда построение переопределяет какие-то элементы, то в мир 1, в общем случае, переходят лишь независимые элементы от переопределенных элементов. например, в примере выше операция * и операция + автоматически перешли в мир 1, при этом использование операции + выродилось.
ссылка же это зависимое (производное) понятие от объекта, потому оно меняется при переходе, если переопределяется понятие объекта.
как именно меняется зависит от того, как оно определено в рамках данной теории.
соответственно, как только ты скажешь, что такое ссылка в рамках теории ООП, то я тебе скажу как именно оно меняется при переходе.
DG>>а что с ним разбираться, если оно сейчас такое же как поле 2 с точностью до взаимно-однозначного отображения S>Можешь указать обратный элемент для true на операции or?
true — это 0, а or — это *, поэтому это требование его не касается.
у 0 для операции * нет обратного элемента, и это зафиксировано в свойствах поля
DG>>>приведи логический вывод. S>>ты сам сказал, что идентичность может быть неопределена.
DG>это лишь означает, что: DG>1. во-первых, для данного программы можно определить как хочется DG>2. во-вторых, что для данной программы такое построение делать не стоит, но из этого не следует, что его не стоит делать для произвольной программы
Это означает что твоя идентичность не позволяет отличать объекты.
DG>>>в построении 0 существуют, в построении 1 — не существуют, пока не приведено конструктивного определения, что такое ссылка S>>Но это не мешает тебе использовать термин для своего построения
DG>ссылка же это зависимое (производное) понятие от объекта, потому оно меняется при переходе, если переопределяется понятие объекта. DG>как именно меняется зависит от того, как оно определено в рамках данной теории.
То есть ты не знаешь, но термином пользуешься. DG>соответственно, как только ты скажешь, что такое ссылка в рамках теории ООП, то я тебе скажу как именно оно меняется при переходе.
DG>>>а что с ним разбираться, если оно сейчас такое же как поле 2 с точностью до взаимно-однозначного отображения S>>Можешь указать обратный элемент для true на операции or?
DG>true — это 0, а or — это *, поэтому это требование его не касается. DG>у 0 для операции * нет обратного элемента, и это зафиксировано в свойствах поля
Да я забыл что у тебя там Xor, а не or.
Давай вернемся к полю 2, где у тебя эквивалентность в качестве аддитивной операции.
Что там у тебя является нулевым элементом?
S>Давай вернемся к полю 2, где у тебя эквивалентность в качестве аддитивной операции. S>Что там у тебя является нулевым элементом?
написано же:
поле 1:
операция + поля: xor
операция * поля: and
нулевой элемент поля: false
единичный элемент поля: true
поле 2:
операция + поля: ==
операция * поля: or
нулевой элемент поля: единичный элемент поля 1 (true)
единичный элемент поля: нулевой элемент поля 1 (false)
DG>>это лишь означает, что: DG>>1. во-первых, для данного программы можно определить как хочется DG>>2. во-вторых, что для данной программы такое построение делать не стоит, но из этого не следует, что его не стоит делать для произвольной программы S>Это означает что твоя идентичность не позволяет отличать объекты.
да, для "плохих" программ не позволяет. зато позволяет в хороших
DG>>>>в построении 0 существуют, в построении 1 — не существуют, пока не приведено конструктивного определения, что такое ссылка S>>>Но это не мешает тебе использовать термин для своего построения
DG>>ссылка же это зависимое (производное) понятие от объекта, потому оно меняется при переходе, если переопределяется понятие объекта. DG>>как именно меняется зависит от того, как оно определено в рамках данной теории. S>То есть ты не знаешь, но термином пользуешься.
я встречал штук 20 определений понятия ссылка (часть из них хорошая, часть не очень).
но на текущий момент, именно ты узурпировал право решать — определения какого авторитета считать правильным.
поэтому я жду, когда ты примешь решение какое определение ссылки ты считаешь правильным.
S>>Давай вернемся к полю 2, где у тебя эквивалентность в качестве аддитивной операции. S>>Что там у тебя является нулевым элементом?
DG>написано же: DG>
DG>поле 1:
DG>операция + поля: xor
DG>операция * поля: and
DG>нулевой элемент поля: false
DG>единичный элемент поля: true
DG>поле 2:
DG>операция + поля: ==
DG>операция * поля: or
DG>нулевой элемент поля: единичный элемент поля 1 (true)
DG>единичный элемент поля: нулевой элемент поля 1 (false)
DG>
Хорошо. Убедил. Здесь мы видим два поля, все определения выполняются. Но что общего с объектными системами? Ты определил систему, где определение идентичности не выполняется. Пусть ты считаешь что его выполнять необязательно, или что оно выполняется, но я вижу что не выполняется.
DG>>>это лишь означает, что: DG>>>1. во-первых, для данного программы можно определить как хочется DG>>>2. во-вторых, что для данной программы такое построение делать не стоит, но из этого не следует, что его не стоит делать для произвольной программы S>>Это означает что твоя идентичность не позволяет отличать объекты.
DG>да, для "плохих" программ не позволяет. зато позволяет в хороших
А ООП идентичность работает для всех программ.
DG>>>ссылка же это зависимое (производное) понятие от объекта, потому оно меняется при переходе, если переопределяется понятие объекта. DG>>>как именно меняется зависит от того, как оно определено в рамках данной теории. S>>То есть ты не знаешь, но термином пользуешься.
DG>я встречал штук 20 определений понятия ссылка (часть из них хорошая, часть не очень). DG>но на текущий момент, именно ты узурпировал право решать — определения какого авторитета считать правильным. DG>поэтому я жду, когда ты примешь решение какое определение ссылки ты считаешь правильным.
Хорошо, предлагай. Со ссылкой на авторитета. А я буду решать
DG>>да, для "плохих" программ не позволяет. зато позволяет в хороших S>А ООП идентичность работает для всех программ.
не для всех, как уже выше разбирали — например, ecma-идентичность не во всех случаях является ООП-идентичность
во-вторых, при конструктивном подходе недоопределенность или противоречия сами по себе не мешают, потому что в большинстве случаев можно сделать доопределение.
например, для .net-а можно взять функцию идентичности (и доопределить ее на основе ecma-identity):
если оба double.IsNan — true
если оба value-type (в том числе и забоксированный) — equals
если оба строка — equals
иначе (оба ссылочный-тип или оба разных видов) — referenceequals
для твоего контрпримера достаточно мою функцию идентичности доопределить как: если трассу не получилось установить, то объекты различные.
это приводит к главному вопросу:
если в одной программе можно построить несколько функций идентичности, то какую лучше выбрать?
и ответ ту которая более полиморфная: с большим кол-ва кода позволяет работать один и тем же образом.
если есть функция идентичности, которая позволяет единым образом обрабатывать изменения immutable-объекта и изменения mutable-объекта, то стоит выбирать именно такую функцию идентичности.
DG>>я встречал штук 20 определений понятия ссылка (часть из них хорошая, часть не очень). DG>>но на текущий момент, именно ты узурпировал право решать — определения какого авторитета считать правильным. DG>>поэтому я жду, когда ты примешь решение какое определение ссылки ты считаешь правильным. S>Хорошо, предлагай. Со ссылкой на авторитета. А я буду решать
ссылка — аксиоматическое (или другими словами неопределяемое через более элементарные понятия) понятие.
описание (оно же свойства):
элемент, посредством которого осуществляется работа с объектом (через ссылку посылаются сообщения реальному объекту).
ссылка — объект в границах локальной системы, через который посылаются сообщения объекту во внешней системе.
обычно ссылка не отчуждаема от текущего контекста (и этим отличается от идентификатора)
пример 1:
возьмем в качестве локальной системы — функцию.
внутри границ такой системы находится только stack-frame (переменные-параметры и локальные переменные).
heap — это внешняя система. и для того, чтобы работать с объектами из внешней системы в переменную помещается ссылка.
пример 2:
локальная система — .net app domain.
объект-RealProxy — есть ссылка на объект из внешней системы.
пример 3:
локальная система — компьютер пользователя
пользовательский интерфейс www.rsdn.ru загруженный в браузер — есть ссылка на объект БД rsdn.ru
DG>>>да, для "плохих" программ не позволяет. зато позволяет в хороших S>>А ООП идентичность работает для всех программ.
DG>не для всех, как уже выше разбирали — например, ecma-идентичность не во всех случаях является ООП-идентичность
В каких не является? Где я был?
DG>во-вторых, при конструктивном подходе недоопределенность или противоречия сами по себе не мешают, потому что в большинстве случаев можно сделать доопределение.
Я бы это назвал "немного ослабить". DG>например, для .net-а можно взять функцию идентичности (и доопределить ее на основе ecma-identity): DG>если оба double.IsNan — true
Обалдеть. А ничего что там могут быть PositiveInfinity и NegativeInfinity?
DG>если оба value-type (в том числе и забоксированный) — equals
Equals от ValueType не годится для идентичности, т.к. позволяет быть идентичными объектам с разными состояниями. DG>если оба строка — equals
То же самое. DG>иначе (оба ссылочный-тип или оба разных видов) — referenceequals
DG>для твоего контрпримера достаточно мою функцию идентичности доопределить как: если трассу не получилось установить, то объекты различные.
В моем контрпримере трассу установить удалось. В частности, "" и "1" входят в одну трассу. Но ты утверждаешь что их идентичность неопределена.
DG>это приводит к главному вопросу: DG>если в одной программе можно построить несколько функций идентичности, то какую лучше выбрать?
Ты сейчас задаешь вопрос уровня "если в одном поле можно построить несколько аддитивных функций, то какую лучше выбрать?"
DG>и ответ ту которая более полиморфная: с большим кол-ва кода позволяет работать один и тем же образом. DG>если есть функция идентичности, которая позволяет единым образом обрабатывать изменения immutable-объекта и изменения mutable-объекта, то стоит выбирать именно такую функцию идентичности.
Именно такая и выбрана в ecma.
DG>>>поэтому я жду, когда ты примешь решение какое определение ссылки ты считаешь правильным. S>>Хорошо, предлагай. Со ссылкой на авторитета. А я буду решать
DG>ссылка — аксиоматическое (или другими словами неопределяемое через более элементарные понятия) понятие. DG>описание (оно же свойства): DG>элемент, посредством которого осуществляется работа с объектом (через ссылку посылаются сообщения реальному объекту).
Не конкретно. Что за элемент? XML? Контроллер памяти? Источник не указан.
DG>ссылка — объект в границах локальной системы, через который посылаются сообщения объекту во внешней системе. DG>обычно ссылка не отчуждаема от текущего контекста (и этим отличается от идентификатора)
DG>пример 1: DG>возьмем в качестве локальной системы — функцию. DG>внутри границ такой системы находится только stack-frame (переменные-параметры и локальные переменные). DG>heap — это внешняя система. и для того, чтобы работать с объектами из внешней системы в переменную помещается ссылка.
DG>пример 2: DG>локальная система — .net app domain. DG>объект-RealProxy — есть ссылка на объект из внешней системы.
DG>пример 3: DG>локальная система — компьютер пользователя DG>пользовательский интерфейс www.rsdn.ru загруженный в браузер — есть ссылка на объект БД rsdn.ru
DG>данное определение предложено DarkGray-ем
DarkGray для меня не авторитет в области выдумывания определений. К тому же определение ссылки основано на определении объекта, с идентичностью которого в определениях DG я наблюдаю серьезные несоответствия с OOP. Кроме того, какие-то системы, контексты, локальности.
На правах, данными мне через узурпирование мной прав решать о правильности определений, говорю — не годится.
DG>>во-вторых, при конструктивном подходе недоопределенность или противоречия сами по себе не мешают, потому что в большинстве случаев можно сделать доопределение. S>Я бы это назвал "немного ослабить". DG>>например, для .net-а можно взять функцию идентичности (и доопределить ее на основе ecma-identity): DG>>если оба double.IsNan — true S>Обалдеть. А ничего что там могут быть PositiveInfinity и NegativeInfinity?
чё? там быть — это где? и чему это мешает?
научись все-таки грамотно формулировать свои сомнения. хотя бы в виде: если принять это допущение, и потом сделать вот так и вот так, то будет жопа.
DG>>если оба value-type (в том числе и забоксированный) — equals S>Equals от ValueType не годится для идентичности, т.к. позволяет быть идентичными объектам с разными состояниями.
в каких сообщений это проявляется?
DG>>это приводит к главному вопросу: DG>>если в одной программе можно построить несколько функций идентичности, то какую лучше выбрать? S>Ты сейчас задаешь вопрос уровня "если в одном поле можно построить несколько аддитивных функций, то какую лучше выбрать?"
выбор аддитивной функции определяет поле в котором происходит работа.
так, например, в булевой логике — аддитивную функцию можно взять хor и будет одно поле, а можно взять == и будет другое поле.
тоже самое и с ооп, для одного и того же кода, можно взять разные функции идентичности, и будет разные ООП с разным делением
DG>>ссылка — аксиоматическое (или другими словами неопределяемое через более элементарные понятия) понятие. DG>>описание (оно же свойства): DG>>элемент, посредством которого осуществляется работа с объектом (через ссылку посылаются сообщения реальному объекту). S>Не конкретно. Что за элемент? XML? Контроллер памяти? Источник не указан.
неопределяемые понятия и не бывают конкретными. пойди посмотри определение точки или множества и найди там конкретность
вот где здесь конкретность?:
В современной аксиоматике геометрии точка является первичным понятием, задаваемым перечнем его свойств.
элемент — это то, что выделили из пространства. некий отдельный рассматриваемый "атом" "пространства".
S>DarkGray для меня не авторитет в области выдумывания определений.
вот именно поэтому в математике и не используют авторитеты, никто же не говорит, что понятие поле правильное потому что его предложил Евклид, Абель или кто-то еще.
в математике (как и в любой точной науке) — правильность определения проверяется лишь по соотношению двух критериев: насколько много из определения можно выводов сделать, и к скольки ситуациям определение можно применить.
Здравствуйте, DarkGray, Вы писали:
DG>>>во-вторых, при конструктивном подходе недоопределенность или противоречия сами по себе не мешают, потому что в большинстве случаев можно сделать доопределение. S>>Я бы это назвал "немного ослабить". DG>>>например, для .net-а можно взять функцию идентичности (и доопределить ее на основе ecma-identity): DG>>>если оба double.IsNan — true S>>Обалдеть. А ничего что там могут быть PositiveInfinity и NegativeInfinity?
DG>чё? там быть — это где? и чему это мешает? DG>научись все-таки грамотно формулировать свои сомнения. хотя бы в виде: если принять это допущение, и потом сделать вот так и вот так, то будет жопа.
Если принять допущение что все double, которые IsNan являются одним объектом, то выходит что ответ на сообщения IsPositive(Negative)Infinity неопределен. Ты мог бы определить одним объектом все даблы < 1.0 с тем же успехом. Да, я помню, для тебя это совершенно не жопа, ты даже пытался определить идентичными даблы, разница которых по модулю меньше епсилон.
DG>>>если оба value-type (в том числе и забоксированный) — equals S>>Equals от ValueType не годится для идентичности, т.к. позволяет быть идентичными объектам с разными состояниями.
DG>в каких сообщений это проявляется?
В каких-нибудь. Например, может проявиться в сообщениях ToString.
DG>>>это приводит к главному вопросу: DG>>>если в одной программе можно построить несколько функций идентичности, то какую лучше выбрать? S>>Ты сейчас задаешь вопрос уровня "если в одном поле можно построить несколько аддитивных функций, то какую лучше выбрать?"
DG>выбор аддитивной функции определяет поле в котором происходит работа. DG>так, например, в булевой логике — аддитивную функцию можно взять хor и будет одно поле, а можно взять == и будет другое поле. DG>тоже самое и с ооп, для одного и того же кода, можно взять разные функции идентичности, и будет разные ООП с разным делением
Да. Но проблемма твоего ООП в том, что твое деление не удовлетворяет идентичности ООП.
DG>>>ссылка — аксиоматическое (или другими словами неопределяемое через более элементарные понятия) понятие. DG>>>описание (оно же свойства): DG>>>элемент, посредством которого осуществляется работа с объектом (через ссылку посылаются сообщения реальному объекту). S>>Не конкретно. Что за элемент? XML? Контроллер памяти? Источник не указан.
DG>неопределяемые понятия и не бывают конкретными. пойди посмотри определение точки или множества и найди там конкретность DG>вот где здесь конкретность?: DG>
DG>В современной аксиоматике геометрии точка является первичным понятием, задаваемым перечнем его свойств.
DG>элемент — это то, что выделили из пространства. некий отдельный рассматриваемый "атом" "пространства".
Я вижу твои определения закручены в кольцо. Идентичность объкта ты определяешь через ссылку, сыслку через объект, атом, пространство и т.п. Что же у тебя все-таки аксиоматичнее? ссылка или объект?
S>>DarkGray для меня не авторитет в области выдумывания определений.
DG>вот именно поэтому в математике и не используют авторитеты, никто же не говорит, что понятие поле правильное потому что его предложил Евклид, Абель или кто-то еще. DG>в математике (как и в любой точной науке) — правильность определения проверяется лишь по соотношению двух критериев: насколько много из определения можно выводов сделать, и к скольки ситуациям определение можно применить.
Я пока не увидел ни одного полезного вывода из твоих определений. И ни одной ситуации, в которой они были бы полезнее, чем ООП аналоги.
Докажи сначала право твоих определений на существование в рамках ООП, т.е. непротиворечивость им.
Начни с того, какой смысл в существовании объекта, который отвечает на сообщения неопределенным образом. Примеры — строки с твоей идентичностью, где объект на сообщение Length может вернуть что угодно... Double с IsPositiveInfinity...
S>Я вижу твои определения закручены в кольцо. Идентичность объкта ты определяешь через ссылку, сыслку через объект, атом, пространство и т.п. Что же у тебя все-таки аксиоматичнее? ссылка или объект?
они оба аксиоматичны.
не путай три различные вещи: определение, способ конструирования и описание. они внешне похожи, но ничего общего между собой не имеют.
вопрос на засыпку — сколько неопределяемых понятий и аксиом в евклидовой геометрии?
в ООП как минимум есть следующие неопределяемые понятия:
объект
состояние
поведение
ссылка
сообщение
отправка/получение сообщения
кстати, в ООП неявно подразумевается, что сообщение объекту может отправляться только через ссылку.
и именно через это объясняется, почему функция F1 может послать сообщение объекту z, а у функции F2 нет способа отправить сообщение объекту z
void F1(Z z)
{
z.SendMessage();
}
void F2()
{
}
void Main()
{
var z= new Z();
F1(z);
F2();
}
S>Докажи сначала право твоих определений на существование в рамках ООП, т.е. непротиворечивость им.
для начала приведи, что чему не должно противоречить.
пока ты не привел вообще ни одного формализованного требования.
S>Начни с того, какой смысл в существовании объекта, который отвечает на сообщения неопределенным образом. Примеры — строки с твоей идентичностью, где объект на сообщение Length может вернуть что угодно...
такого противоречия нет — при одновременном использовании трасс и понятия версионного объекта
S> Double с IsPositiveInfinity...
Здравствуйте, DarkGray, Вы писали:
S>>Я вижу твои определения закручены в кольцо. Идентичность объкта ты определяешь через ссылку, сыслку через объект, атом, пространство и т.п. Что же у тебя все-таки аксиоматичнее? ссылка или объект?
DG>они оба аксиоматичны.
DG>не путай три различные вещи: определение, способ конструирования и описание. они внешне похожи, но ничего общего между собой не имеют.
Ок, не буду
DG>вопрос на засыпку — сколько неопределяемых понятий и аксиом в евклидовой геометрии?
Считай, что засыпался. Я этим вопросом не занимался. Но имею мнение. Евклид описывал понятия. Аналитическая геометрия их определяет на основе теории множеств. Аксиом 5 штук.
DG>в ООП как минимум есть следующие неопределяемые понятия: DG>объект DG>состояние DG>поведение DG>ссылка DG>сообщение DG>отправка/получение сообщения
У меня такое ощущение, что все на что ты хотел начихать, ты засунул в неопределяемые понятия.
DG>кстати, в ООП неявно подразумевается, что сообщение объекту может отправляться только через ссылку.
В ООП очень много что неявно подразумевается, на что ты забил. Например, то что объект сохраняет идентичность на все время своего существования. А что только через ссылку — это ты придумал.
DG>и именно через это объясняется, почему функция F1 может послать сообщение объекту z, а у функции F2 нет способа отправить сообщение объекту z DG>
Имеешь право объяснять именно "через это". Мое право — неудовлетворяться таким объяснением.
S>>Докажи сначала право твоих определений на существование в рамках ООП, т.е. непротиворечивость им.
DG>для начала приведи, что чему не должно противоречить. DG>пока ты не привел вообще ни одного формализованного требования.
Приводил.
S>>Начни с того, какой смысл в существовании объекта, который отвечает на сообщения неопределенным образом. Примеры — строки с твоей идентичностью, где объект на сообщение Length может вернуть что угодно...
DG>такого противоречия нет — при одновременном использовании трасс и понятия версионного объекта
То что ты это отрицаешь не исчерпывает противоречия.
S>> Double с IsPositiveInfinity...
DG>тут тем более проблемы нет.
Есть.
Здравствуйте, DarkGray, Вы писали:
DG>не для всех, как уже выше разбирали — например, ecma-идентичность не во всех случаях является ООП-идентичность DG>во-вторых, при конструктивном подходе недоопределенность или противоречия сами по себе не мешают, потому что в большинстве случаев можно сделать доопределение. DG>например, для .net-а можно взять функцию идентичности (и доопределить ее на основе ecma-identity): DG>если оба double.IsNan — true DG>если оба value-type (в том числе и забоксированный) — equals DG>если оба строка — equals DG>иначе (оба ссылочный-тип или оба разных видов) — referenceequals
Отлично. Я надеюсь, вы понимаете, что расширили модель ООП, введя в неё помимо объектов ещё и "экземпляры значимых типов", которые ведут себя по другому?
Само ООП в вашем расширении совершенно не нуждается, и прекрасно работает без него. С возможностью расширять модель ООП никто не спорил с самого начала. Вы пытались доказать, что можно получить ООП, ослабив требования к одной из составляющих модели. Увы.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>Я вижу твои определения закручены в кольцо. Идентичность объкта ты определяешь через ссылку, сыслку через объект, атом, пространство и т.п. Что же у тебя все-таки аксиоматичнее? ссылка или объект?
DG>они оба аксиоматичны.
DG>не путай три различные вещи: определение, способ конструирования и описание. они внешне похожи, но ничего общего между собой не имеют.
DG>вопрос на засыпку — сколько неопределяемых понятий и аксиом в евклидовой геометрии?
DG>в ООП как минимум есть следующие неопределяемые понятия: DG>объект DG>состояние DG>поведение DG>ссылка DG>сообщение DG>отправка/получение сообщения
Неа. Почти всё определяемо.
Ссылка — это математическое понятие с определённым "математическим поведением". То есть для ссылки определены операции
— сравнения ссылок (вводящая отношение эквивалентности ссылок)
— снятия ссылки (возможность отправить сообщение объекту по ссылке)
объект — это математическое понятие с определённым математическим поведением. В частности, есть понятие "поведение", которое определяется набором всех возможных реакций на все возможные сообщения.
сообщение — это элемент множества возможных сообщений. Способов строить множество сообщений — много. Однако от сообщений требуется только различимость (она нужна для того, чтобы можно было описывать поведение).
состояние объекта — это возможность для него по-разному реагировать на одинаковые сообщения. В полностью детерминистической модели состояние объекта однозначно определяется предысторией отправленных ему сообщений.
И так далее.
DG>кстати, в ООП неявно подразумевается, что сообщение объекту может отправляться только через ссылку.
Да.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Ссылка — это математическое понятие с определённым "математическим поведением". То есть для ссылки определены операции S>- сравнения ссылок (вводящая отношение эквивалентности ссылок) S>- снятия ссылки (возможность отправить сообщение объекту по ссылке)
это зафиксированы свойства — это не означает, что при этом однозначно определено, что такое ссылка.
так же как фиксируется, что у точки нет размерности, но это не означает, что понятие точки определено.
S>объект — это математическое понятие с определённым математическим поведением. В частности, есть понятие "поведение", которое определяется набором всех возможных реакций на все возможные сообщения. S>сообщение — это элемент множества возможных сообщений. Способов строить множество сообщений — много. Однако от сообщений требуется только различимость (она нужна для того, чтобы можно было описывать поведение). S>состояние объекта — это возможность для него по-разному реагировать на одинаковые сообщения. В полностью детерминистической модели состояние объекта однозначно определяется предысторией отправленных ему сообщений.
так можно определять, но здесь появилось новое понятие "реакция на сообщение".
так же есть множества всяких нюансов — следующее поведение одинаковое или нет?
Здравствуйте, DarkGray, Вы писали: DG>это зафиксированы свойства — это не означает, что при этом однозначно определено, что такое ссылка.
Ссылка — это то, что удовлетворяет этим свойствам. Не очень понятно, что вы называете термином "однозначно". Вот что такое рациональные числа — определено однозначно или неоднозначно? Ссылки определены не хуже рациональных чисел.
DG>так можно определять, но здесь появилось новое понятие "реакция на сообщение".
Оно не является атомарным, а определяется в терминах существующих. Реакцией на сообщение является отправка от 0 до N сообщений другим объектам.
DG>так же есть множества всяких нюансов — следующее поведение одинаковое или нет? DG>?
Не очень понятно, что означают ваши формулы, но судя по всему — нет, не одинаковое.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>это зафиксированы свойства — это не означает, что при этом однозначно определено, что такое ссылка. S>Ссылка — это то, что удовлетворяет этим свойствам. Не очень понятно, что вы называете термином "однозначно". Вот что такое рациональные числа — определено однозначно или неоднозначно? Ссылки определены не хуже рациональных чисел.
рациональное число задано в формате "<существительное> + <свойства>": рациональное число — это число, которое удовлетворяет свойству: представляемое несократимой обыкновенной дробью.
или другими словами — берется элемент известного множества "число", и на него накладываются ограничения.
из какого множества берется "ссылка"? можно ли ссылки брать из множества "объект"?, сейчас определение про это ничего не говорит
DG>>так можно определять, но здесь появилось новое понятие "реакция на сообщение". S>Оно не является атомарным, а определяется в терминах существующих. Реакцией на сообщение является отправка от 0 до N сообщений другим объектам.
из этого определения вытекает, что в понятие "поведение" не входит изменение состояния.
это так и есть? или это ты просто забыл указать?
S> сообщение — это элемент множества возможных сообщений. Способов строить множество сообщений — много
как соотносятся множества сообщений и объектов? пересекаются? одно входит в другое? строго не пересекающиеся? имеют общие вырожденные точки?
как соотносятся между собой множества ссылки и объекты? множества ссылки и сообщения?
на все эти вопросы необходимо ответить, если речь идет о математических определениях
S>Если принять допущение что все double, которые IsNan являются одним объектом, то выходит что ответ на сообщения IsPositive(Negative)Infinity неопределен. Ты мог бы определить одним объектом все даблы < 1.0 с тем же успехом.
вижу, в этой фразе хвост не стыкуется с началом, т.к. double.IsNan(double.NegativeInfinity) возвращает false
Здравствуйте, DarkGray, Вы писали:
S>>Если принять допущение что все double, которые IsNan являются одним объектом, то выходит что ответ на сообщения IsPositive(Negative)Infinity неопределен. Ты мог бы определить одним объектом все даблы < 1.0 с тем же успехом.
DG>вижу, в этой фразе хвост не стыкуется с началом, т.к. double.IsNan(double.NegativeInfinity) возвращает false
Действительно. Я думал, что он вернет true. Лопух.
Но проблема не снимается, т.к. для такого дабла, который (Double.IsNan(x) == true), а он один по определению идентичности DG, существует примерно 2^52-1 вариантов ответа BitConverter.DoubleToInt64Bits(x).
S>Но проблема не снимается, т.к. для такого дабла, который (Double.IsNan(x) == true), а он один по определению идентичности DG, существует примерно 2^52-1 вариантов ответа BitConverter.DoubleToInt64Bits(x).
дальше есть несколько вариантов:
1. если эта функция в программе не используется, то пофигу что она там возвращает.
2. если используется и можно считать, что функция BitConverter.DoubleToInt64Bits — частично случайная: для double.IsNan — она случайно выбирает битовое представление из определенного множества.
и программе такого предположения достаточно, то тоже нет проблемы
это все необходимо для уменьшения кол-ва рассматриваемых вариантов поведения программы, что упрощает задачу доказательства корректности программы
S>>Но проблема не снимается, т.к. для такого дабла, который (Double.IsNan(x) == true), а он один по определению идентичности DG, существует примерно 2^52-1 вариантов ответа BitConverter.DoubleToInt64Bits(x).
DG>дальше есть несколько вариантов: DG>1. если эта функция в программе не используется, то пофигу что она там возвращает. DG>2. если используется и можно считать, что функция BitConverter.DoubleToInt64Bits — частично случайная: для double.IsNan — она случайно выбирает битовое представление из определенного множества. DG>и программе такого предположения достаточно, то тоже нет проблемы
DG>это все необходимо для уменьшения кол-ва рассматриваемых вариантов поведения программы, что упрощает задачу доказательства корректности программы
Что бы уменьшить кол-во рассматриваемых вариантов поведения программы достаточно оперировать эквивалентностью Double.IsNan на определенном множестве операций без подмены идентичности.
И уж точно перевод DoubleToInt64Bits из разряда детерминированных не упростит доказательство корректности там где она используется.
S>Что бы уменьшить кол-во рассматриваемых вариантов поведения программы достаточно оперировать эквивалентностью Double.IsNan на определенном множестве операций без подмены идентичности.
Здравствуйте, DarkGray, Вы писали:
S>>Что бы уменьшить кол-во рассматриваемых вариантов поведения программы достаточно оперировать эквивалентностью Double.IsNan на определенном множестве операций без подмены идентичности.
DG>покажи как используется эквивалентность при доказательстве корректности(или некорректности) следующего кода: DG>http://www.rsdn.ru/forum/philosophy/4553822.aspx?tree=tree
Вообще-то я не подписывался анализировать корректность-некорректность императивного кода. Но для того что бы показать некорректность этого, достаточно его рассахарить. Тогда будет видно что построенные функции умножают не соответствующее значение из последовательности на себя, а умножают на себя значение, равное последнему элементу последовательности.
Для доказательства того что это значение совпадает с последним значением последовательности не нужна эквивалентность по IsNan.
Здравствуйте, DarkGray, Вы писали:
S>>Для доказательства того что это значение совпадает с последним значением последовательности не нужна эквивалентность по IsNan.
DG>где формальное доказательство?
Я же написал, что не подписывался делать формальные доказательства императивного кода. Но направление вот:
class X { public double x; }
X x = new X();
for (var tmp in seq)
x.x = tmp;
Если ты не можешь доказать что при непустом seq в x будет лежать последнее значение из seq после выполнения цикла без того что бы испортить идентичность — то это не мои проблемы.
Что конкретно тебя смущает? Присваивание?
S>Если ты не можешь доказать что при непустом seq в x будет лежать последнее значение из seq после выполнения цикла без того что бы испортить идентичность — то это не мои проблемы.
не понятно, какое это отношение имеет к исходному примеру.
там присвоения полей вообще не было.
S>Что конкретно тебя смущает? Присваивание?
эквивалентность чего с чем используется и на каком основании
Здравствуйте, DarkGray, Вы писали:
S>>Если ты не можешь доказать что при непустом seq в x будет лежать последнее значение из seq после выполнения цикла без того что бы испортить идентичность — то это не мои проблемы.
DG>не понятно, какое это отношение имеет к исходному примеру. DG>там присвоения полей вообще не было.
Вот что интересно. Если ты действительно понятия не имеешь, какое это имеет отношение к исходному коду, то как ты собрался доказывать корректность/некорректность исходного кода? Дай угадаю... С помощью твоей идентичности, которая к исходному коду вообще никакого отношения не имеет, ну то есть абсолютно никакого?
S>>Что конкретно тебя смущает? Присваивание?
DG>эквивалентность чего с чем используется и на каком основании
Я прозивел преобразование кода, эквивалентное преобразованию кода компилятором C#. На том основании, что я знаю, что он производит такое преобразование.
Если ты умудришься формально доказать корректность/некорректность этого кода благодаря своей идентичности и не раскрывая конструкций foreach, анонимные методы и т.п., то флаг тебе.
DG>>эквивалентность чего с чем используется и на каком основании S>Я прозивел преобразование кода, эквивалентное преобразованию кода компилятором C#. На том основании, что я знаю, что он производит такое преобразование.
т.е. ты используешь эквивалентность понятий переменная и объект?, но при этом также утверждаешь, что переменная не является объектом? интересно живешь...
DG>>>эквивалентность чего с чем используется и на каком основании S>>Я прозивел преобразование кода, эквивалентное преобразованию кода компилятором C#. На том основании, что я знаю, что он производит такое преобразование.
DG>т.е. ты используешь эквивалентность понятий переменная и объект?, но при этом также утверждаешь, что переменная не является объектом? интересно живешь...
Я не использовал эквивалентность этих понятий, они и не эквивалентны. Я заменил локальную переменную полем объекта, ровно как и компилятор. Для этого не требуется эквивалентность переменной и объекта.
DG>>т.е. ты используешь эквивалентность понятий переменная и объект?, но при этом также утверждаешь, что переменная не является объектом? интересно живешь... S>Я не использовал эквивалентность этих понятий, они и не эквивалентны. Я заменил локальную переменную полем объекта, ровно как и компилятор. Для этого не требуется эквивалентность переменной и объекта.
ты использовал, что переменная эквивалентна полю объекта, а из это следует, что переменная эквивалентна объекту.
или более формально, ты использовал, что:
1. объявление переменной типа T эквивалентно созданию объекта Переменная с полем T
2. присвоение переменной эквивалентно присвоение полю
3. получение значения переменной эквивалентно получению значения поля
доказательство:
4. поле объекта эквивалентно свойству объекта без доп. поведения
5. свойство объекта эквивалентно двум методам GetValue/SetValue
6. (из 2, 4, 5) присвоение переменной эквилентно вызову метода SetValue
7. (из 3, 4, 5) получение значения переменной эквивалентно вызову метода GetValue
из 1, 6, 7:
8. объявление переменной типа T эквивалентно созданию объекта Переменная<T>
9. присвоение переменной эквивалентно вызову метода SetValue
10. получение значения из переменной эквивалентно вызову метода GetValue
Здравствуйте, DarkGray, Вы писали:
DG>или другими словами — берется элемент известного множества "число", и на него накладываются ограничения.
А можно в студию определение известного множества "число"?
DG>из какого множества берется "ссылка"? можно ли ссылки брать из множества "объект"?, сейчас определение про это ничего не говорит
Из некоторого счётного множества. Можно брать и из множества "объект", определение это никак не ограничивает.
DG>>>так можно определять, но здесь появилось новое понятие "реакция на сообщение". S>>Оно не является атомарным, а определяется в терминах существующих. Реакцией на сообщение является отправка от 0 до N сообщений другим объектам.
DG>из этого определения вытекает, что в понятие "поведение" не входит изменение состояния. DG>это так и есть? или это ты просто забыл указать?
Модель ООП не требует возможности обнаружить изменение состояния иначе, как по поведению. Поэтому определение реакции на сообщение не включает в себя никаких рассуждений об изменении состояния.
S>> сообщение — это элемент множества возможных сообщений. Способов строить множество сообщений — много
DG>как соотносятся множества сообщений и объектов? пересекаются? одно входит в другое? строго не пересекающиеся? имеют общие вырожденные точки?
Определение никак не ограничивает соотнесение множеств ссылок, объектов, и сообщений. Однако, в зависимости от выбора этих соотношений получаются разные модели. Например, если вложить множество ссылок в множество объектов, то сразу возникнут штуки типа "ссылка на ссылку", которые могут оказаться нежелательными.
Могут возникнуть артефакты, связанные с поведением объекта-сообщения.
DG>как соотносятся между собой множества ссылки и объекты?
Каждому элементу множества ссылок сопоставлен ровно один объект.
DG>множества ссылки и сообщения?
Ну, ссылка может содержаться в сообщении. Это означает, что может существовать некоторая функция Extract(m), которая определена на некотором подмножестве множества сообщений, которая сопоставляет сообщению ссылку. Таких функций может быть сколь угодно много, с частично пересекающимися областями определения.
DG>на все эти вопросы необходимо ответить, если речь идет о математических определениях
Сделать это легче, чем кажется.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>или другими словами — берется элемент известного множества "число", и на него накладываются ограничения. S>А можно в студию определение известного множества "число"?
Число́ — абстракция, используемая для количественной характеристики и нумерации объектов.
а вот абстракция, количественная характеристика и нумерация — это уже неопределяемые понятия.
DG>>из какого множества берется "ссылка"? можно ли ссылки брать из множества "объект"?, сейчас определение про это ничего не говорит S>Из некоторого счётного множества. Можно брать и из множества "объект", определение это никак не ограничивает.
т.е. объект может являться ссылкой?
и в следующем коде — объект X является ссылкой? у него есть оба зафиксированные тобой свойств — сравнение ссылок и снятие ссылки
class X<T>
{
public T GetValue(){..}
..
}
DG>>>>так можно определять, но здесь появилось новое понятие "реакция на сообщение". S>>>Оно не является атомарным, а определяется в терминах существующих. Реакцией на сообщение является отправка от 0 до N сообщений другим объектам.
DG>>из этого определения вытекает, что в понятие "поведение" не входит изменение состояния. DG>>это так и есть? или это ты просто забыл указать? S>Модель ООП не требует возможности обнаружить изменение состояния иначе, как по поведению.
уничтожение объекта себя самим — это часть поведения или часть состояния?
S>Поэтому определение реакции на сообщение не включает в себя никаких рассуждений об изменении состояния.
это уже связка трех разных определений: Поведение, Наблюдаемое поведение и Инкапсуляции.
Инкапсуляция говорит, что в рамках ООП значимым является лишь Наблюдаемое поведение, и если через наблюдение невозможно отличить одно поведение от другого, то поведения считаются одинаковыми.
S>>>Оно не является атомарным, а определяется в терминах существующих. Реакцией на сообщение является отправка от 0 до N сообщений другим объектам.
т.е. исходя из твоих определений поведение объектов X считается различным? а как это можно наблюдать?
и исходя из твоих определений поведение объектов Y и Y1 считается одинаковым?
class X
{
public M(){x.M1();}
protected X1 x = new X1();
protected class X1
{
public void M1(){}//ничего не делает
}
}
class Y
{
public void M(){}
}
class Y1
{
public void M(){x = -x;}
protected int x;
}
Здравствуйте, DarkGray, Вы писали: DG>Число́ — абстракция, используемая для количественной характеристики и нумерации объектов.
Ну, то есть под такое определение числа подходит всё, что угодно, если оно используется для количественной характеристики и нумерации объектов.
В целом видно, что мы добрались до неопределимого понятия.
DG>>>из какого множества берется "ссылка"? можно ли ссылки брать из множества "объект"?, сейчас определение про это ничего не говорит S>>Из некоторого счётного множества. Можно брать и из множества "объект", определение это никак не ограничивает.
DG>т.е. объект может являться ссылкой?
DG>и в следующем коде — объект X является ссылкой? у него есть оба зафиксированные тобой свойств — сравнение ссылок и снятие ссылки DG>
DG>class X<T>
DG>{
DG> public T GetValue(){..}
DG> ..
DG>}
DG>
Из приведённого фрагмента кода непонятно, является ли объект ссылкой или нет, т.к. не приведено определение операции сравнения ссылок.
Но если его корректно доопределить, то да, объекты, построенные на основе такого класса могут служить в качестве ссылок.
DG>уничтожение объекта себя самим — это часть поведения или часть состояния?
Для ответа на этот вопрос нужно сначала решить, существует ли такая вещь, как уничтожение объекта. ООП не требует от модели детерминистической финализации.
DG>это уже связка трех разных определений: Поведение, Наблюдаемое поведение и Инкапсуляции.
DG>Инкапсуляция говорит, что в рамках ООП значимым является лишь Наблюдаемое поведение, и если через наблюдение невозможно отличить одно поведение от другого, то поведения считаются одинаковыми.
В целом да, но инкапсуляция — это свойство связки Поведения и Состояния. Примерно так же, как требование Дистрибутивности не даёт построить поле на вообще любых двух бинарных операциях.
DG>т.е. исходя из твоих определений поведение объектов X считается различным? а как это можно наблюдать?
Различным. Есть обмен сообщениями. В зависимости от подробностей модели и её реализации, способы наблюдения могут быть разными.
DG>и исходя из твоих определений поведение объектов Y и Y1 считается одинаковым?
Да.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>уничтожение объекта себя самим — это часть поведения или часть состояния? S>Для ответа на этот вопрос нужно сначала решить, существует ли такая вещь, как уничтожение объекта. ООП не требует от модели детерминистической финализации.
не требует и обратного, соответственно для общности необходимо решить — это поведение или состояние, если уж сейчас даются определения для ООП вообще, а не для ООП без детерминистической финализации
DG>>это уже связка трех разных определений: Поведение, Наблюдаемое поведение и Инкапсуляции.
DG>>Инкапсуляция говорит, что в рамках ООП значимым является лишь Наблюдаемое поведение, и если через наблюдение невозможно отличить одно поведение от другого, то поведения считаются одинаковыми. S>В целом да, но инкапсуляция — это свойство связки Поведения и Состояния. Примерно так же, как требование Дистрибутивности не даёт построить поле на вообще любых двух бинарных операциях.
не спорю
DG>>т.е. исходя из твоих определений поведение объектов X считается различным? а как это можно наблюдать? S>Различным. Есть обмен сообщениями. В зависимости от подробностей модели и её реализации, способы наблюдения могут быть разными.
здесь важно что наблюдение делается клиентским объектом (тот который имеет ссылку на объект) в рамках используемого им подмножества сообщений (интерфейса объекта), а не произвольным сторонним наблюдателем.
произвольный сторонний наблюдателем всегда может послать сообщение — покажите мне память объекта, или сериализуйте мне объект,
и тогда не получится на следующий вопрос никогда ответить "да".
и если клиентский объект на используемом им подмножестве сообщений не может выявить отличие (в том числе косвенно через другие объекты), то поведение считается одинаковым
DG>>и исходя из твоих определений поведение объектов Y и Y1 считается одинаковым? S>Да.
Здравствуйте, DarkGray, Вы писали: DG>не требует и обратного, соответственно для общности необходимо решить — это поведение или состояние, если уж сейчас даются определения для ООП вообще, а не для ООП без детерминистической финализации
Вы опять лезете дальше, чем нужно. Базовая модель ООП не обязана ничего говорить о том, что должно считатся в надстроенных над ней моделях.
Если хочется заняться построением модели с детерминистической финализацией, то придётся ответить ещё на много вопросов — в том числе и на то, что делать с невалидными ссылками. Совершенно незачем тащить всю эту грязь в базовую модель.
DG>здесь важно что наблюдение делается клиентским объектом (тот который имеет ссылку на объект) в рамках используемого им подмножества сообщений (интерфейса объекта), а не произвольным сторонним наблюдателем.
В рамках ООП-модели у нас нет произвольного стороннего наблюдателя.
DG>произвольный сторонний наблюдателем всегда может послать сообщение — покажите мне память объекта, или сериализуйте мне объект, DG>и тогда не получится на следующий вопрос никогда ответить "да".
Совершенно необязательно. Модель не требует от объектов какой-то специальной реакции на сообщения типа "покажите мне память объекта", или "сериализуйте мне объект".
Мы можем ввести специальный объект "независимый наблюдатель", не нарушая черноты объектных ящиков — достаточно потребовать от фабричных объектов, чтобы они стучали наблюдателю обо всех создаваемых объектах. Если этого не делать, то у нас получится "релятивистская модель" с конусом причинности и прочими штуками.
DG>и если клиентский объект на используемом им подмножестве сообщений не может выявить отличие (в том числе косвенно через другие объекты), то поведение считается одинаковым
В базовой модели нет понятия "клиентский объект".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Если хочется заняться построением модели с детерминистической финализацией, то придётся ответить ещё на много вопросов — в том числе и на то, что делать с невалидными ссылками. Совершенно незачем тащить всю эту грязь в базовую модель.
но как минимум ты согласен, что ООП с детерминистической финализацией является ООП?
DG>>здесь важно что наблюдение делается клиентским объектом (тот который имеет ссылку на объект) в рамках используемого им подмножества сообщений (интерфейса объекта), а не произвольным сторонним наблюдателем. S>В рамках ООП-модели у нас нет произвольного стороннего наблюдателя.
есть только два варианта:
либо в моделе утверждения фиксируются относительные для конкретного наблюдателя (например, который сидит в каждом конкретном объекте),
либо в моделе утверждения фиксируются абсолютно (и тогда появляется сторонний произвольный наблюдатель)
DG>>произвольный сторонний наблюдателем всегда может послать сообщение — покажите мне память объекта, или сериализуйте мне объект, DG>>и тогда не получится на следующий вопрос никогда ответить "да". S>Совершенно необязательно. Модель не требует от объектов какой-то специальной реакции на сообщения типа "покажите мне память объекта", или "сериализуйте мне объект".
речь не об этом.
ты зафиксировал, что следующие объекты имеют одинаковое поведение
class Y
{
public void M(){}
}
class Y1
{
public void M(){x = -x;}
protected int x;
}
но в любом ЯП это не так, т.к. всегда можно послать сообщение, которое покажет, что внутри Y1 есть x, которого нет в Y.
S>Мы можем ввести специальный объект "независимый наблюдатель", не нарушая черноты объектных ящиков — достаточно потребовать от фабричных объектов, чтобы они стучали наблюдателю обо всех создаваемых объектах.
S>Если этого не делать, то у нас получится "релятивистская модель" с конусом причинности и прочими штуками.
чем это плохо, и кому мешает?
DG>>и если клиентский объект на используемом им подмножестве сообщений не может выявить отличие (в том числе косвенно через другие объекты), то поведение считается одинаковым S>В базовой модели нет понятия "клиентский объект".
дай тогда свое название для множества объектов, которые могут посылать сообщения конкретному объекту.
Здравствуйте, DarkGray, Вы писали: DG>но как минимум ты согласен, что ООП с детерминистической финализацией является ООП?
Конечно.
DG>есть только два варианта: DG>либо в моделе утверждения фиксируются относительные для конкретного наблюдателя (например, который сидит в каждом конкретном объекте), DG>либо в моделе утверждения фиксируются абсолютно (и тогда появляется сторонний произвольный наблюдатель)
Не совсем. Утверждения вроде "не существует ни одного конкретного наблюдателя, сидящего в каком-либо конкретном объекте, который был бы способен наблюдать явление хххх" фиксируется абсолютно, но никакого стороннего наблюдателя не требует.
DG>но в любом ЯП это не так, т.к. всегда можно послать сообщение, которое покажет, что внутри Y1 есть x, которого нет в Y.
Это потому, что "любой ЯП" имеет средства нарушения или обхода инкапсуляции, которые расширяют базовую модель.
DG>чем это плохо, и кому мешает?
Ничем.
DG>дай тогда свое название для множества объектов, которые могут посылать сообщения конкретному объекту.
Ну, это все объекты, обладающие ссылками на этот объект. Да, с этой точки зрения недостижимый объект не имеет ни поведения, ни состояния.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>но в любом ЯП это не так, т.к. всегда можно послать сообщение, которое покажет, что внутри Y1 есть x, которого нет в Y. S>Это потому, что "любой ЯП" имеет средства нарушения или обхода инкапсуляции, которые расширяют базовую модель.
вот именно поэтому ООП в реальной программе всегда рассматривается на конкретном подмножестве сообщений, а не на всех сообщениях которые только возможно.
Здравствуйте, Sinclair, Вы писали:
V>>Что ближе к такой последовательности 3-х операций РА, являющихся решением обоих уравнений: V>>tmp1 = X x Y V>>tmp2 = ограничение(x1=y1) tmp1 V>>result = проекция{x1, x2, .. xN} tmp2 V>>Можно записать в виде одной формулы, не суть, все равно будет 3 примитивные операции РА в ней. S>Или две. Задача решается через переименование и полуджоин.
Что есть полуджоин в РА?
S>Или через equi-джоин и проекцию. Но не суть.
equi-джоин в РА тоже нет. Есть соединение (произвольное), но им обычно не пользуюсь как базовым, бо он по определению составной: (A TIMES B) WHERE c, где каждая из двух операций уже входит в базис. Т.е. в любом случае составная операция получается после разложения на примитивные операции (как мои первые две строчки), независимо от того, как бы ты записал в исходной формуле.
S>Суть в том, что порядок вычисления X и Y не важен. Можно сначала рассчитать Y, а потом уже X. А можно — наоборот. Нам не важно, какие формулы стоят на местах X и Y, т.к. эти формулы заведомо не имеют побочных эффектов. Именно в этом суть декларативности РА.
Мы уже это обсуждали. Это не контраргумент к тому, о чем я говорил, бо порядок вычисления аргументов операций не определен в РА, так же как во многих, даже императивных языках. Я приводил пример. А если он не определен, то спор ни о чем. Что на что менять-то? Поэтому снова и снова скатываться на удобную тему порядка вычислений аргументов операций контрпродуктивно. Речь была о порядке вычисления зависимых операций. Я попросил вполне конкретно попробовать поменять местами приведенные операции, чтобы понять о чем речь. В принципе мне фиолетово, если хочешь цепляться за порядок вычисления аргументов, я могу уточнить (хотя уже уточнял не раз), что речь была о зависимых операциях РА. Тем более, что говорилось "в общем случае". Собсно, это и есть специфика РА, что в общем случае у нас одни операции ТРЕБУЮТ ПРЕДВАРИТЕЛЬНЫХ других операций, например, обязательно проекции/переименования перед OR, AND и остальными теоретико-множественными операциями, бо они работают ТОЛЬКО над совместимыми отношениями. Т.е. как ни крути, а придется обеспечивать совместимость ДО операций. Тоже самое относительно декартова произведения — в случае одноименных атрибутов в исходных отношениях переименование обязательно должно быть выполнено ДО произведения. И тут тебе ни одна из приведенных ранее формул преобразований/оптимизаций не поможет поменять этот порядок вещей. Т.е. даже если вариантов приведения аргументов к нужным много (а их почти бесконечное кол-во), то они все должны быть выполнены ДО самой операции продукции. Такова специфика, на которую многократно намекал. Вроде бы на поверхности.
V>>Нету сайд-эффектов, а последовательность вычислений есть. V>>Понимаешь... злобные функциональщики малость лукавят. Ф-ий подход зиждется на процедурном, а тот не отрицает зависимость результата от порядка вычисления. Просто коль отсутствуют побочные эффекты, то аргументы ф-ий можно вычислять в произвольном порядке. Но это малость не то же самое, что зависимые вычисления делать в произвольном порядке. А я на этой зависимости настаивал изначально, мне случай независимых аргументов неинтересен, на то они и независимые. S>Вы делали всеобщее утверждение про фиксированность порядка вычислений в РА. Вам показали что нет, не всегда он фиксирован.
Еще раз, отсюда и до бесконечности: в общем случае порядок вычислений менять невозможно.
V>>Не совсем так. Я уже пояснял каждый пример, где речь действительно идет об оптимизации. Например, повторные ограничения никто не делает, они объдиняются по AND ф-ий ограничений. но это происходит еще до РА, еще во время автоматической генерации алгоритма запроса. S>В целом правильно, хотя и несколько наивно.
Почему наивно? Есть типовые шаблоны перевода структурных формул над отношениями в плоские над атрибутами + правила, управляющими преобразованиями ограничений при подстановке шаблонов. Вот на этом уровне обычно всё и происходит. Т.е. исходные ограничения разбиваются (если это возможно) и его составляющие помещаются как можно раньше к аргументам. Напомню, что в РА аргументами ограничений являются только значения отрибутов и скаляры. Если атрибуты одного отношения — прямо идет к выборке как первой операции над отношением. Если больше, чем из одной — то на первую же "точку" вычислений, где становятся доступны все необходимые атрибуты. Я понимаю, что приведенные преобразования познавательны и полезны (они даже расшифровывают физический смысл некоторых операций), но на практике преобразования ограничений на уровне РА уже не делают. Незачем. Делают преобразования только через подстановку отношений, управляемую зависимостями. Как раз поэтому настаивал на возможности автоматического выбора индекса по таблице, бо СУБД знает достоверно о зависимостях м/у индексами и таблицей.
V>>>>Я таки настаиваю ее изобразить. Потому что если это именно ф-ия как "черный ящик", то аргументы будут для такой ф-ии вычислены, хоть и не будут использованы внутри самой ф-ии, а если не черный ящик, то таки хотелось посмотреть на примере SQL (откуда она пойдет в РА). G>>>SQL, в отличие от РА предполагает аппликативный порядок вычислений. Найдешь реализацию SQL где это не так — спокойно сделаю.
V>>И где это ограничение явно указано? G>В семантике функций.
Незачет. Похоже, ты не понимаешь, что есть ф-ия в РА.
V>>Опять же, ты не забыл замечание про минимум 2 вида аналитических выражений в РА — это собственно выражения РА и выражения-ограничения в выборке или разновидностях соединений. Какой уровень ты имел ввиду? G>А ты какие когда говорил про коммутативность?
Коммутативность справедлива на обоих уровнях. На то она и коммутативность. В РА почти половина операций комутативны. А если брать ф-ию ограничения, то она, в отличие от операций РА, не ограничена неким базисом. Ф-ия ограничения может быть произвольной математической ф-ий возвращающей предикат или приводимой к предикату. Ф-ия не обязана иметь аналитический вид, она может быть "черным ящиком" от аргументов. Единственное ограничение накладывается на аргументы ф-ии: они должны быть атрибутами или скалярами. Это именно то, почему спекуляции на порядке вычислений на уровне ф-ии ограничения РА работает плохо — ведь атрибуты и скаляры считаются уже вычисленными для РА, их НЕ НАДО ВЫЧИСЛЯТЬ.
V>>Меняет. Ты же походя присвоил коммутативность некоей произвольной ф-ии, показав затем, что она нихрена не коммутативна из своего определения. Меня это улыбнуло, понятное дело, просто любопытно таки докопаться до всей цепочки рассуждений, которое могло ТАКОЕ породить.
G>Я привел функцию, которая формальному определению коммутативности соответствует. У тебя какое-то другое определение?
Уровень РА не предоставляет ср-в для определения пользовательский ф-ий ограничений. Т.е. или пиши в аналитическом виде, и тогда рассуждения о необхомости вычисления атрибутов в твоих примерах становятся неприменимы. Или используй ф-ию как "внешнюю" по отношению к РА, т.е. как ф-ия "черный ящик" с аргументами, но тогда все аргументы должны быть в эту ф-ию поставлены, независимо от того, использует она их внутри или нет. А раз все аргументы должны быть подставлены, мы сможем использовать эту ф-ию только в той точке вычислений, где доступны все ее аргументы. Т.е. я понимаю, что ты хотел там выразить, типа того, что раз аргумент не используется, его можно не вычислять, и из-за этого можно поменять порядок применения ф-ии, например применить ранее, там где еще нет игнорируемого аргумента... но это малость мимо специфики РА, бо повторюсь, или аналитический вид ф-ии полностью доступен, или полностью недоступен, и тогда никаких предположений делать не стоит.
V>>Мешает то, что ф-ии ограничения, где аргументами идут отношения — это уровень исчисления кортежей, но не уровень РА. Задача РА как раз преобразовать "структурные" формулы РИ в "плоские" операции РА, где ф-ии ограничения будут в терминах операций над атрибутами кортежей. Курить определение ограничения в РА. G>То есть ты признаешь что далеко не любые коммутативные функции соответствуют тому что ты написал. Теперь давай выясним какие все таки соответствуют.
Соответствуют любые коммутативные из всего доступного мат-аппарата, если речь о ф-ии ограничения.
Если же речь о ф-иях из базиса РА (8 операций), то в их определении сказано, какие из них коммутативные, а какие нет.
V>>Попробуй кстате, "просто поменять вычисления местами" (С), мне любопытно. Замечания про ленивые vs энергичные я уже делал — ничего не меняется на уровне вычисления атрибутов кортежей.
Вопрос оставляю в силе. Бо даже если я и выражался "коряво", предполагая, что собеседники понимают, о чем речь, то вот в конкретном примере двусмысленности быть не может. Хорошо видно, что именно имелось ввиду.
V>>Я это понимаю, и даже давал больше по этой теме, но ты невнимательно читал. Да, именно, уровень РА нужен для того, чтобы в его терминах породить ВСЕВОЗМОЖНЫЕ решения исходной формулы, потому что коль на уровне РА отсутствуют ф-ии над отношениями, т.е. отстуствует вложенность в ограничениях, т.е. отсутствует рекурсия формул, становится возможным произвести оценку сложности операций. Так вот, там, где некий автоматический движок, перечисляющий всевозможные решения в терминах РА знает об декомпозиции исходной схемы на отношения, он может не просто породить s'(t), он может породить s'(t'), где t' — другое отношение, но сохраняющее зависимости исходной схемы. Прочувствовал разницу?
G>Совершенно не понял о чем ты.
Я еще тогда понял, что ты не понял. Речь о том, что некая исходная схема R {ABCDE} с зависимостями A->BC, C->DE, может быть нормализована к одной из форм следующей декомпозицией:
X:{ABC}, Y:{CDE}. + некая избыточность для прикладных нужд: Z:{CE}.
Так вот, формулы на уровне РИ задают условия над доменами и атрибутами, и если нам нужен в ответе или условии атрибут E, то он может быть как минимум в 2-х отношениях декомпозиции, поэтому будут существовать минимум два решения в терминах РА, которые неприводимы один к другому на уровне РА, т.к. будут оперировать различными исходными отношениями Y и Z, но будут приводимы на уровне РИ, через исходные зависимости.
G>Я ведь говорю не только о некоторых преобразованиях в пределах одной операции, а в перестановке вычислений для композиции операций. И это при том что композиция в общем случае некоммутативна.
Если ты все еще о вычислении аргументов, то давай эту тему прикроем. Будем считать, что порядок вычисления аргументов операций базиса РА не важен. А аргументы ф-ий ограничений заведомо являются вычисленными по своему определению.
G>>>Конечно движок субд опирается на семантику того что происходит и некоммутативность некоторых операций в общем случае ему не помеха.
V>>Так вот, к большому пребольшому сожалению, движки СУБД не имеют понятия о семантике, т.к. обычно не реализовано одно из самых важных правил Кодда, позволяющее сохранять зависимости исходного прикладного отношения и проведенной конкретной декомпозиции. СУБД не делает никаких предположений относительно избыточности данных, принадлежащих одному домену и одному "логическому" атрибуту в рамках всей схемы.
G>Это тебя совсем не туда понесло.
Наверно ты не понял, что я написал. Так и подмывает спросить, профильное ли было образование...
V>>Нету сайд-эффектов, а последовательность вычислений есть. G>Она всегда есть, но она не совпадает с порядком записи аргументов и композиции функций.
Ты имеешь ввиду порядок записи на бумаге?
Представь лучше в виде направленного графа/дерева. Не важен будет лишь порядок вычисления независимых узлов. Мне от этой нубской очевидности уже просто становится лень отмахиваться. Детсад.
V>>Понимаешь... злобные функциональщики малость лукавят. Ф-ий подход зиждется на процедурном, а тот не отрицает зависимость результата от порядка вычисления. Просто коль отсутствуют побочные эффекты, то аргументы ф-ий можно вычислять в произвольном порядке. Но это малость не то же самое, что зависимые вычисления делать в произвольном порядке. А я на этой зависимости настаивал изначально, мне случай независимых аргументов неинтересен, на то они и независимые. G>А что значит "зависимые вычисления" если у нас есть ленивость? А по сути ничего.
Ленивость ничего не меняет на уровне кортежей. Попробуй хотя бы немного применить ленивость к любому простому примеру — поймешь о чем речь. Тем паче, что существует два вида ленивости — это при вычислении скаляров (предикаты) и при вычислении мн-в (курсоры). Оба варианта ничего не меняют ни для ф-ии ограничения, ни для операций РА.
Нет никакого изменения порядка в случае ленивости, бо если идет обращение к атрибуту кортежа промежуточного результата, например, то этот атрибут будет вычислен в любом случае согласно того самого графа вычислений. Формулы ограничений задаются над кортежами, и абсолютно все-равно, каким образом вычисляются множества этих кортежей, когда рассматривается порождение одного кортежа. Т.е. порядок вычисления мн-в и атрибутов — это малость ортогонально и даже не оговаривается и из формулы никак не следует, чтобы можно было обсуждать "порядок". Я настаивал исключительно на порядке операций РА. Выше Синклеру обрисовал малость подробнее, в чем именно там специфика.
G>Если итоговый результат не не нужен или нужен не полностью, то "зависимые вычисления" можно и не вычислять.
Их придется вычислять. Ты не узнаешь, нужен ли кортеж или не нужен, не породив его. И опять же, порядок вычисления атрибутов в кортеже вообще из формул никак не следует, это тебя не в ту степь понесло.
G>И опять таки коммутативность тут никакой роли не играет.
Он играет при доступности аналитического вида ф-ии ограничения, т.к. позволяет проводить некоторые декомпозиции операций РА. С натяжкой можно сказать, меняя порядок вычислений при этом. Хотя, более строго — проводя ДРУГИЕ (преобразованные) вычисления.
Здравствуйте, vdimas, Вы писали:
V>Что есть полуджоин в РА? http://en.wikipedia.org/wiki/Relational_algebra#Semijoin_.28.E2.8B.89.29.28.E2.8B.8A.29
S>>Или через equi-джоин и проекцию. Но не суть.
V>equi-джоин в РА тоже нет. http://en.wikipedia.org/wiki/Relational_algebra#.CE.B8-join_and_equijoin
V>Мы уже это обсуждали. Это не контраргумент к тому, о чем я говорил, бо порядок вычисления аргументов операций не определен в РА, так же как во многих, даже императивных языках. Я приводил пример.
Простите, но ваш пример с C++ ничего не доказывает.
V>>>Не совсем так. Я уже пояснял каждый пример, где речь действительно идет об оптимизации. Например, повторные ограничения никто не делает, они объдиняются по AND ф-ий ограничений. но это происходит еще до РА, еще во время автоматической генерации алгоритма запроса. S>>В целом правильно, хотя и несколько наивно.
V>Почему наивно? Есть типовые шаблоны перевода структурных формул над отношениями в плоские над атрибутами + правила, управляющими преобразованиями ограничений при подстановке шаблонов. Вот на этом уровне обычно всё и происходит.
То, что вы рассказываете — это неполный пересказ алгоритма работы эвристического оптимизатора запросов. Они вышли из моды примерно в конце девяностых, когда в промышленность вошли cost-based оптимизаторы. Так что бывает, что делают и повторные ограничения, если это выгодно. Поэтому я и говорю, что наивно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
V>>ЧТД. Наконец ты сознался. Не верно. Декларативность — это относительное понятие, ортогональное к побочным эффектам. Если есть неких два уровня абстракции, то один из них декларативен к другому, если примитивы более высокоуровневой абстракции выражаются в терминах операций над примитивами более низкоуровневой. S>Это определение — ваше личное изобретение. Оно не имеет никакого отношения к традиционной трактовке разницы между императивным и декларативным программированием.
В вики не смотрел?
Согласно второму определению, программа «декларативна», если она написана на исключительно функциональном, логическом или языке программирования с ограничениями. Выражение «декларативный язык» иногда употребляется для описания всех таких языков программирования как группы, чтобы подчеркнуть их отличие от императивных языков.
Итого, не так давно, буквально уже на моей памяти, появилось это "второе" определение, которое является искажением исходного термина (приведенного там же в Вики как первое). Например, программирование с ограничениями (или логическое как частный случай) подходит под декларативность по-определению. А функциональные языки приписали сюда злобные функциональщики, как ср-во борьбы с императивным программированием. Дело в том, что императивная программа тоже может быть декларативной и наоборот, функциональная может ей не быть, согласно первоначального определения. Скажу больше, любой язык с аннотацией типов заведомо содержит элементы декларативности. Но есть же нетипизированные функциональные, которые вовсе не декларативны "из коробки", а декларативны только на прикладном уровне, достижимого согласно исходного определения.
В общем, второе определение я оставлю лишь недобросовестным фанам функционального программирования, бо оно неверно в общем случае.
S>Но это бы ничего, если бы определение имело хоть какой-то практический смысл. Но нет — не имеет. В частности, по вашему определению РА одновременно более декларативна чем РИ, и менее декларативна чем оно же, и мы возвращаемся к тому, с чего начали: РА и РИ одинаково декларативны.
Неодинаково. В общем случае одна операция РИ требует нескольких операций из базиса РА, обратное неверно. Опять же, операции базиса РА не описывают характер результата, а только лишь действия над ним. Т.е. если у нас более одной операции, то в рамках каждой отдельной операции РА мы не знаем характер аргументов, поэтому не можем достоверно судить о характере результата. В то время как РИ описывает именно характер результата. Но на прикладном уровне, когда мы будем реализовывать эту РА, то сами операции РА могут служить высокоуровневыми инструкциями по отношению к некоему следующему уровню, и будут являться по отношению к нему декларативными, в контексте одной независимой операции РА.
V>>>>С результатами других операций все еще хуже, бо они получены в порядке индекса одного из исходных вариантов и могут не быть сортированы по отношению к требуемой следующей соединительной операции. S>>>А могут и быть. V>>Ну так вот тебе и умножение вместо сложения в том случае, где нет. Видел порой в плане запроса операцию сортировки промежуточных результатов перед join? А сложность алгоритмов внешней сортировки какова? S>Вы путаете общее с частным, делая всеобщее утверждение на основе некоторго частного случая.
Не смеши. Наоборот, это общий случай для СУБД. Реляционные базы изобретены для данных, заведомо больших размера оперативной памяти. Для данных же, помещающихся в оперативной памяти на гарвардской или фон-неймановской архитектуре есть куча других, на порядки более эффективных техник, чем эмуляция ассоциативной памяти в реляционных СУБД. В общем, тот факт, что иногда реляционные СУБД юзают не потому что они реляционные, а потому они надежные — это и есть скорее частный случай, чем общий.
S>>>Нет. Реляционная модель была разработана не для джойнов по "произвольной формуле". А джойны по значению атрибута отлично работают и для больших внешних хранилищ. V>>Еще раз — только при упорядоченности внешнего ключа одной и основного ключа другой таблицы. S>Зачем вы продолжаете делать некорректные всеобщие утверждения? Очевидно, что для перехода от O(M*N) к O(M*log(N)) достаточно отсортированности только одного аргумента.
Мнэээ... Речь изначально была об O(M+N), если я ничего не пропустил. Сорри, не могу здесь поддержать твой очередной спор с самим собой.
V>>У меня тоже свой опыт... когда были пни-200, то нейтивный сервер, со складом-бухгалтерией, использующий DCOM для клиентов в одноранговой сети с низлежащей базой на JET просто летал как бабочка, а поставили выделенный MS SQL в кач-ве базы на втрое более мощный комп — и все стало гораздо печальнее минимум на год, пока еще вдвое характеристики компов не подросли. Это и спасло при росте базы, потому как пришлось уже делать меньше оперативный период, что не всегда удобно. S>Я ваш опыт обсуждать не буду. Не глядя в исходники невозможно сказать, движок ли виноват или плохо написанное приложение.
Когда речь идет о простых выборках, напр. join по основному и вненему ключу, то всё слишком очевидно, чтобы предполагать непонятно что. Исходники смотрел на предмет чувствительности к отсутствию выравнивания физических данных, когда идут вперемешку атрибуты, некратные 32 бит (на тот момент). Бо машины того времени гораздо хуже читали невыровненные данные, чем нынешние.
V>>Тогда твоя боязнь очень избирательна, на примере разницы логического и физического плана запроса. Ты взял, да и привязался к конкретной реализации конкретной СУБД. S>Я нигде не привязался к конкретной реализации. Разница между логическим и физическим планами есть везде, где есть оптимизатор запросов. Читайте литературу.
Надо полагать, "читайте литературу по MS SQL"?
S>Нет, я не считаю, что сами по себе знания во вред. Вред приносят заблуждения. Вы продолжаете их изрекать со скоростью 2-5 заблуждения за пост. И я вижу некоторую систему в отдельных заблуждениях. Как глядя на реку, я не вижу валунов, лежащих на дне; но по ряби на поверхности я могу делать выводы об их наличии и расположении.
Гы, я вижу аналогичное, только даже не заблуждения, а невладение предметом. И попытки рассуждать "чисто теоретически" без владения спецификой обсуждаемого. Например, часть якобы моих заблуждений относится таки к твоим, например относительно способа хранения блобов и требования фиксированного размера записи для кластерных индексов. Или характерны спекуляции относительно порядка вычисления аргументов в РА. Детсад как он есть. Невладение спецификой. Даже если я в первый раз некоректно выразился, то владей ты — давно бы поправил, бо понял бы о чем речь. Дык нет, я и сам сразу же поправился, но ты перестать спекулировать на можешь. Итого, сдается мне, что рябь это вызвана больше ветром пустых слов и придирок к формулировкам, в условиях непонимания о чем даже идет речь. Я уже пытался одернуть, что по этой теме изначально пытался беседовать как с людьми "в теме", но потом мы съехали на вот это никого не красящее разжевывание на пальцах, как здесь: http://www.rsdn.ru/forum/philosophy/4563653.1.aspx
Должно быть уже просто стыдно за такой уровень максимум 3-го курса обучения от профей с более 10-тилетним стажем (или даже еще большим).
S>Так же и здесь — глядя на форум, я не вижу валунов у вас в голове. Но они проявляются в виде ряби на поверхности — некорректных утверждений, которые вы делаете.
Пока что согласился только насчет оценок быстродействия кластерного индекса, и то, там бабка на двое сказала. Бо даже лишняя страница по тем временам на том размере ОП (т.е. не та политика кеширования была), с теми скоростями жестки дисков и т.д., могла и дать такую ощутимую разницу. Боюсь, на современных ОС и современном железе воспроизвести сей эффект будет сложновато. Только поэтому предпочел согласиться. А все остальное якобы мои заблуждения — было бы неплохо доказать, бо пока что ни пример — то мимо, причем очень мимо... Скажем так, торчат уши сугубо личного опыта, весьма одностороннего при этом (коль уже не первый раз странная реакция на замечания относительно соотношения ОП и размера данных, сценариев использования реляционных СУБД и т.д.), к тому же, по одной всего СУБД.
Еще желание фехтовать и понтоваться будет, или таки ближе телу?
V>>Ты ткнул несоответствием в плане возможной неуникальности промежуточных и даже итоговых данных. V>>Давай уже ближе к телу. Обоснуй, как более широкие возможности SQL мешают использовать наработки более узкой модели? S>ОМГ. Вы сейчас какое конкретно моё утверждение пытаетесь оспорить? Найдите его и процитируйте. Я понимаю, вам удобнее спорить с тезисом, которого я не высказывал. Но всё же постарайтесь держаться в рамках беседы.
Утверждение о неприменимости аппарата РА на разных уровнях. Напомню: оспаривалось на уровне SQL со стороны программиста, и на уровне выбора индексов таблицы со стороны СУБД, при составлении плана запроса по этому SQL. Утверждалось тобой неоднократно. Приводились примеры несоответствия модели. Неоднократно ты настаивал на несоответствии теории м-в, лежащей в основе операций РА, и реальных записей в СУБД, которые могут повторяться. Чушь собачья оба аргумента, если всерьез. С самого начала языки, типа SQL, использовались прямо в обычных язках программирования. Нет абсолютно никакого противоречия выполнить одну операцию по одним "законам" математики, но результат этой операции обработать далее уже по неким другим "законам". Вот так примерно позволяют современные развитые диалекты SQL. Утверждать, что более широкая модель не позволяет пользоваться наработками более узкой — несомненно ошибочно. Ты пытался меня переубедить многократно. Насчет второго аргумена, повтора записей, многократно просил продемонстрировать механизм нарушения работоспособности операций РА — не увидел. И не увижу, бо теория мн-в требует лишь различимости элементов, а они уже различимы как-то со стороны любого механизма реализации РА, коль он способен порождать дублирующиеся записи. Это аксиоматично, т.к. это значит, что сей механим различает элементы как-то еще, помимо значений атрибутов. Не зря в SQL встроили ALL или DISTINCT, т.е. способность различать элементы таки прямо декларируется.
V>>Таки придется, иначе просто заумная балаболка. Реализация всегда отличается от модели, на то она и модель, я не понимаю, почему у тебя проблема конкретно в СУБД. S>Да у меня-то нигде проблем нет. Я вам СУБД привёл как один только пример. Я не виноват, что вы полезли в дебри, в которых плохо разбираетесь.
Если ты чего-то плохо понимаешь, это не значит, что я плохо разбираюсь. Это может значить, что я плохо объясняю, т.к. не всегда сразу вижу, что именно непонятно. Иногда требуется несколько итераций, как с несчастным NULL. Заметь, в первых постах я давал совсем уж мало деталей и рассуждений, бо считал, что общаюсь с коллегами, многое и так должно быть понятно. К сожалению, сие не так, для доказательств своих утверждений приходится рассуждения раскладывать чуть ли не на молекулы. Это скучно уже давно.
V>>Ведь обыгрывают переполнения целых чисел в программах? S>Да, я вам даже привёл пример на эту тему.
Потому и напомнил. Что различия реализации и модели есть, а для 99% сценариев не помеха. А где помеха — там есть совсем простые паттерны обхода ограничения реализации.
V>>И даже ограничения по точности чисел в плавающей. Однако же не мешает пользоваться всем аппаратом математики в вычислениях. S>Ну, таки мешает. Я вам даже пример привёл на эту тему.
И я показал, что таки не очень мешает. И оценка в 1% от таких сценариев — это еще очень оптимистично, бо я с переполнениями борюсь даже далеко не в каждом проекте, где многие тысячи целочисленных переменных.
S>А уж в числах с плавающей запятой совсем копец: там аппаратом математики вещественных чисел пользоваться практически вовсе нельзя.
Ну-ну, не разгоняйся так быстро. Я такими аппаратами пользуюсь, что поверь, придумать их самому, специально под реализации вещественных чисел — ну просто никак. Например, в области обнаружения и обработки сигналов. Всего навсего погрешности округлений представляют как аддитивный шум, поэтому всё несоответствие реализации и модели сводится к оценке шума (тем более достоверно известен его спектральный состав), т.е. к достижению требуемого отношения сигнал/шум. И для этого тоже аппарат есть — "энтропийный": H + Y = 1 (Взаимосвязь энтропии и информации). А формула самой энтропии физику по образованию должна быть известна. Точно так же как должны быть известны правила сложения источников белого шума, например. Всё решаемо, не надо паники. Фактически выводится на кончике пера для каждого оператора/преобразователя для конкретной разрядности и соотношения граничной интересующей частоты и частоты квантования.
S>Но давайте не будем ещё и в плавающую запятую лезть — у меня не хватит энергии на всё.
Гы, почему нет? Мне уже весело. РА использовать нельзя, математику использовать нельзя... Синусы и косинусы я тоже не имею права вычислять?
V>>Улыбнуло, я думал ты уже понял, что тебе говорили. V>>Покажи-ка мне стоимость нахождения записи в случае кластерного индекса внутри страницы, если размер самой записи нефиксированный? S>Что вы называете "нахождением"? Указать, где начинается запись? Или прочесть некоторое поле F, не входящее в ключ индекса? Если второе — то стоимость в терминах логических чтений, очевидно, равна log(N, KeysPerPage)+ PagesPerRecord, где PagesPerRecord — количество страниц, занятых записью.
э нет, имеется ввиду стоимость поиска внутри уже прочитанной страницы. Логическое чтени — это конечно здорово, бо внешняя память медленная. Да только ресурсов процессора практически не ест, DMA всю работу само делает. А вот проход потом по записям внутри страницы — это уже 8к надо прогнать через кеш процессора, если размер записи не будет фиксированный. А вот это уже очень даже ест разделяемые ресурсы, т.е. даже те, где логические чтения не требуются.
S>Встречный вопрос: а что, для некластерного индекса ситуация будет какой-то другой?
Да, для некластерного указан точный адрес записи, в то время как для кластерного указан адрес диапазона с точностью до страницы. Фиксированный размер записи позволит найти запись двоичным поиском или по золотому сечению, резко уменьшив кол-во сравнений ключа с требуемым. Ну и там кеши проца и всё такое тоже играют рояль на современных многоуровневых кешах.
S>И, кстати, выходные прошли. Что там у вас со смелым экспериментом по определению количества логических чтений в кластерных и некластерных индексах? Удалось получить разницу хотя бы в одну страницу?
Пример надо модифицировать, чтобы получить разницу в страницу. Остальные соображения уже высказал в этом же посте выше.
S>Я ничего не путаю. Я понимаю, что вы пытаетесь обосновать порядок вычисления аргументов одних операций (над отношениями) коммутативностью других (над атрибутами).
А только это и тянет на изменение порядка зависимых операций.
S>Тем не менее принципиальным остаётся отсутствие побочных эффектов в запросах.
Детсад как он есть. Как еще побочные эффекты в операциях read-only? Их нет в таких сценариях даже в самых императивных языках. А ты можешь сдвинуться чуть дальше уровня 0, разве не интересно?
S>Поэтому когда мы берём дерево реляционных операций, листья в нём могут вычисляться в любом порядке. Это даже если мы не рассматриваем все эти эквивалентности, которые позволяют нам ещё и перестраивать само дерево.
Хе, вот только я хотел показать суть спекуляций на порядке вычисления аргументов на примере графа выражений (как выше показал твоему коллеге), ты и сам догадался. Хотя я самого начала попытался подобные спекуляции отрезать, сказав, что не интересует порядок вычисления НЕЗАВИСИМЫХ аргументов. Но ты так-то пяток постов именно по независимым и прошелся, увлекательно общаясь сам с собой. Красава. Нет чтобы спросить (коль сразу в голове специфика не нарисовалась), что именно я имел ввиду, говоря, что важна последовательность операций. Ведь что-то же подвигнуло утверждать это неоднократно? Не любопытно было? Ну натурально, вроде я не только в Политике отмечаюсь, да и кода за все эти годы выложил всякого достаточно на многих наглухо разных языках, вплоть до такого: http://www.contextfreeart.org/gallery/view.php?id=2496 Т.е. как бы таки понятно, что как минимум хоть каким-то программистом, но работаю , т.е. твой оппонент хоть как-то должен понимать, что если речь идет о независимых аргументах, то при тум здесь вообще обсуждение порядка их вычисления? Даже пример С++ был, где порядок вычисления вообще не определен by design, во как!!! Но ты же будешь мне пытаться это же самое объяснять примерно еще пяток постов, правильно? Ну не детсад, а? Скажу честно, на всю эту скукотищу мне просто было лень отвечать. Ведь не поспоришь с молодыми, что философия давно превратилась в УГ. Ни воображения, ни полета мысли. Хождения по кругу уровня детсада и понты, больше ничего.
S>>>Понятно. Просто есть два движка с одинаковым названием: Jet Blue и Jet Red. Внутри они принципиально разные. V>>Ну, в VB тоже была своя встроенная ADO, так же была либа для С и ADO-обертка над ней в MFC. S>Обёртки тут ни при чём. Я про engine. В MS Access использовался Jet Red. Jet Blue используется в Microsoft Exchange и Active Directory.
S>Что именно вы собрались "обыгрывать" в дополнительной таблице T2? Вынести туда IK и ссылку на PK основной таблицы? Ну так для чтения атрибутов A1..Ax вы получите по-прежнему log(N) чтений на поиск значения, + log(N)+M чтений на доступ к основной таблице.
Хм, потеря контекста... Никакого PK на основную таблицу не требуется. Иначе не было смысла в этой избыточной. В этой таблице должны быть ровно те атрибуты, что нужны для сценария/сценариев, которые обслуживает наша избыточность. Была задача — поиметь более одного кластерного индекса, коль единственный по условию мы отдали одному из внешних ключей, как я рекомендовал.
S>Если вы планируете включить в T2 что-то из A1..Ax, то их же можно включить в тот же неуникальный индекс и иметь те же преимущества доступа за log(N) без накладных расходов, связанных с поддержкой отдельной таблицы.
Это зависит от того, насколько более широкий такой "расширенный" индекс выйдет. Более широкий — более дорогой даже в выборке. Конечно, ради пары полей int32 овчинка может выделки не стоить, но я не собирался обсуждать количественные эффекты, а просто ответил на твой вопрос: "а зачем?". Надеюсь, ответил. К тому же, упорядоченность кластерного индекса работает хорошо для всяких join в терминах эффективности, невыразимых в логических чтениях. Например, очень эффективно читать страницы, идущие подряд на диске, тогда нам сильно помогает кеш низлежащей ОС, со всякими новомодными технологиями, и даже сами современные диски со встроенным упреждающим чтением.
V>>Для случая вставки в кластерный индекс всегда трудоемкость минимум O(n), помимо операции обновления дерева индекса, которая будет одинаковой стоимости что для исходной таблицы, что для избыточной. Но с этой сложностью борются, оставляя "зазоры" после удаления, чтобы свести ее ближе к логарифму. S>Откуда вы взяли трудоёмкость вставки в O(N)? Стоимость всегда логарифмическая — это же дерево.
Дело в том, что страницы данных кластерного индекса связаны м/у собой, что позволяет перебирать их подряд при всяких join без обращения к дереву индекса. Т.е. стоимость будет стремиться к логарифмической, только если если резервировать зазоры в данных, а если не резервировать, то все данные справа от вставки придется двигать. Внутри страницы двигают по-любому и вообще стараются поддерживать некий однородный коэф заполнения.
Ясно, это не базис РА, это комплексная операция. Идите, как ты любишь говорить, читайте букварь. Характерно, что по твоей же ссылке дана формула этой операции в терминах РА над другой комплексной операцией, для которой, в свою очередь дана расшифровка в базисе:
Так же характерно, что операция декартового произведения в РА есть, ссылка на нее в формулах есть, но определения её в статье, похоже, нет. Это баг статьи, надо слать замечание на доработку.
Туда же.
Хотя пример показательный. Эти комплексные операции отражают самые популярные сценарии в языке SQL. Вот тебе пример того, как целая формула из РА рассматривается как единое целое, т.е. та самая оценка по сложности может быть дана не над базисной операцией, а уже над такой комплексной.
V>>Мы уже это обсуждали. Это не контраргумент к тому, о чем я говорил, бо порядок вычисления аргументов операций не определен в РА, так же как во многих, даже императивных языках. Я приводил пример. S>Простите, но ваш пример с C++ ничего не доказывает.
Он доказывает наличие спекуляций вокруг известных вещей. ИМХО, за неимением чего сказать по самой сути вопроса. Мне, по аналогии с тем, как ты вцепился в эти аргументы, теперь десяток раз копипастить, какие именно врожденные ограничения реляционной алгебры требуют определенного порядка операций?
V>>>>Не совсем так. Я уже пояснял каждый пример, где речь действительно идет об оптимизации. Например, повторные ограничения никто не делает, они объдиняются по AND ф-ий ограничений. но это происходит еще до РА, еще во время автоматической генерации алгоритма запроса. S>>>В целом правильно, хотя и несколько наивно.
V>>Почему наивно? Есть типовые шаблоны перевода структурных формул над отношениями в плоские над атрибутами + правила, управляющими преобразованиями ограничений при подстановке шаблонов. Вот на этом уровне обычно всё и происходит. S>То, что вы рассказываете — это неполный пересказ алгоритма работы эвристического оптимизатора запросов. Они вышли из моды примерно в конце девяностых, когда в промышленность вошли cost-based оптимизаторы. Так что бывает, что делают и повторные ограничения, если это выгодно.
Покажи пример, где выгодно.
S>Поэтому я и говорю, что наивно.
Скорее, от отсутствия опыта по таким преобразованиям. Упомянутые алгоритмы пребирают всевозможные комбинации решений уровня РА для исходной формулы РИ. Хотя я это говорил уже не раз, видать ты подзабыл. А как затем затраты оценивают на уровне РА — мы уже прошли с самого начала. И кстати, что такое "эвристический алгоритм" — я понятия не имею.
Здравствуйте, vdimas, Вы писали:
S>>Это определение — ваше личное изобретение. Оно не имеет никакого отношения к традиционной трактовке разницы между императивным и декларативным программированием.
V>В вики не смотрел? V>В общем, второе определение я оставлю лишь недобросовестным фанам функционального программирования, бо оно неверно в общем случае.
И какое это имеет отношение к изобретённому вами определению? Я с
V>Неодинаково. В общем случае одна операция РИ требует нескольких операций из базиса РА, обратное неверно.
Ну начинается. Вы собрались ещё и метрику "количества операций" вводить? Это всё равно заведёт вас в тупик — именно поэтому ваша идея определения декларативности не получила широкого распространения.
V>Опять же, операции базиса РА не описывают характер результата, а только лишь действия над ним.
Да ладно! Как раз характер результата они и описывают. Скажем, оператор "сигма" никаких действий не описывает. Он просто говорит "результат будет содержать только кортежи, удовлетворяющие указанному ограничению". Что это по-вашему, как не характер результата?
V>Не смеши. Наоборот, это общий случай для СУБД. Реляционные базы изобретены для данных, заведомо больших размера оперативной памяти.
Вы невнимательно читаете. V>Мнэээ... Речь изначально была об O(M+N), если я ничего не пропустил. Сорри, не могу здесь поддержать твой очередной спор с самим собой.
К счастью, в форуме записаны все ходы. "Изначально" речь шла о том, что вы почему-то заложили O(N*M*K) в стоимость операции join трёх составляющих:
Насчет порядка: если некая соединительная операция из 3-х (грубо) составляющий выполняется в 4 раза быстрее, что каждая в среднем стала выполняться быстрее в корень 3-й степени из 4.
Я вам тактично намекнул, что для того, чтобы это было так, нужно сочетание большого количества факторов, которые редко встречаются в жизни. Нужно, чтобы объём всех отношений был больше объёма доступных буферов, и чтобы джоин был по произвольной формуле, а не по равенству атрибутов.
Более реалистичный случай — join по внешнему ключу — стоит O(N*log(M)) независимо от размера отношений N и M. А для star-join с тремя составляющими стоимость будет O(N*log(M*K)). Так что если всё вместе выполняется в 4 раза быстрее, то каждая из операций ускорилась вовсе не в корень третьей степени из четырёх.
V>Когда речь идет о простых выборках, напр. join по основному и вненему ключу, то всё слишком очевидно, чтобы предполагать непонятно что.
Ну, судя по вашим перлам про кластерные индексы и про оценки стоимости джойнов, очевидных вещей вообще не существует. Объяснять надо буквально каждую запятую.
Многие приложения, построенные по принципу select N+1 и client-side join, прекрасно работают на встроенных движках, и даже на тупом ISAM.
И, естественно, со страшной силой начинают сливать при переходе на клиент-серверную архитектуру, потому что там это честный roundtrip с парсингом и исполнением каждого запроса. Поэтому всякий раз, как я вижу упоминание тормозов при переходе с фокспра на оракл или с аксесса на MSSQL, я начинаю подозревать худшее.
Но это, естественно, не единственное объяснение. Понятно, что, скажем, в линейном чтении с локального диска любой dBase порвёт любой сиквел как тузик грелку. Поэтому я и написал, что не могу делать выводы о вашем опыте, не глядя в исходники приложения.
V>Надо полагать, "читайте литературу по MS SQL"?
Я вам давал ссылку. "Системы баз данных. Полный курс".
V>Гы, я вижу аналогичное, только даже не заблуждения, а невладение предметом. И попытки рассуждать "чисто теоретически" без владения спецификой обсуждаемого. Например, часть якобы моих заблуждений относится таки к твоим, например относительно способа хранения блобов и требования фиксированного размера записи для кластерных индексов.
О да, конечно. Я жду с нетерпением результатов ваших замеров, которые вы планировали провести на выходных.
V>Пока что согласился только насчет оценок быстродействия кластерного индекса, и то, там бабка на двое сказала. Бо даже лишняя страница по тем временам на том размере ОП (т.е. не та политика кеширования была), с теми скоростями жестки дисков и т.д., могла и дать такую ощутимую разницу.
Да-да, разницу в "десять-пятнадцать страниц". Я понял. Но я же говорю не о том, что ваш конкретный проект работал как-то не так. Я говорю ровно про то, что ваш подход к исследованию мира даёт вот такие вот результаты: вы увидели некий эффект, и вместо того, чтобы разобраться, поставили кластерные индексы на полочку "тормозное г". С тех пор и память стала другая, и диски несколько другие, но ментальная модель кластерных индексов в вашей голове изменений не претерпела — потому, что там монолит. Нет границы между архитектурой кластерных индексов и её реализацией.
V>Боюсь, на современных ОС и современном железе воспроизвести сей эффект будет сложновато.
Боюсь, вы по-прежнему не понимаете предмета обсуждения. Количество логических чтений в MS SQL никак не зависит ни от ОС, ни от железа. Запрос, который я привёл, покажет те же результаты на вашем мега-сервере, что и на моём ноутбуке. Только у меня дождаться результатов с pageCount = 100000 будет трудно, потому что ограничена скорость записи на винт.
V>Только поэтому предпочел согласиться. А все остальное якобы мои заблуждения — было бы неплохо доказать, бо пока что ни пример — то мимо, причем очень мимо...
Да без проблем.
V>Утверждение о неприменимости аппарата РА на разных уровнях. Напомню: оспаривалось на уровне SQL со стороны программиста, и на уровне выбора индексов таблицы со стороны СУБД, при составлении плана запроса по этому SQL.Утверждалось тобой неоднократно. Приводились примеры несоответствия модели. Неоднократно ты настаивал на несоответствии теории м-в, лежащей в основе операций РА, и реальных записей в СУБД, которые могут повторяться. Чушь собачья оба аргумента, если всерьез. С самого начала языки, типа SQL, использовались прямо в обычных язках программирования. Нет абсолютно никакого противоречия выполнить одну операцию по одним "законам" математики, но результат этой операции обработать далее уже по неким другим "законам".
Всё правильно. Вот только я никаких противоречий и не декларировал. Я объяснял, что одних законов РА недостаточно для функционирования реальных СУБД. И что нужно понимать, где начинаются "дополнительные подробности". Иначе можно запросто попасть впросак, написав бред типа "стоимость операции join пропорциональна O(N*M)".
V>Потому и напомнил. Что различия реализации и модели есть, а для 99% сценариев не помеха. А где помеха — там есть совсем простые паттерны обхода ограничения реализации.
В программировании все помехи — исключительно в голове. Именно поэтому так важно хорошо во всём разбираться.
V>И я показал, что таки не очень мешает. И оценка в 1% от таких сценариев — это еще очень оптимистично, бо я с переполнениями борюсь даже далеко не в каждом проекте, где многие тысячи целочисленных переменных.
Ну я рад за ваши проекты. Это всего лишь означает, что ваши программы — некорректны, просто вас не везде поймали за руку ваши QA. И, кстати, из двух предоженных вами решений проблемы с переполнением при построении компаратора одно не работает.
V>Ну-ну, не разгоняйся так быстро. Я такими аппаратами пользуюсь, что поверь, придумать их самому, специально под реализации вещественных чисел — ну просто никак. Например, в области обнаружения и обработки сигналов. Всего навсего погрешности округлений представляют как аддитивный шум, поэтому всё несоответствие реализации и модели сводится к оценке шума (тем более достоверно известен его спектральный состав), т.е. к достижению требуемого отношения сигнал/шум. И для этого тоже аппарат есть — "энтропийный": H + Y = 1 (Взаимосвязь энтропии и информации). А формула самой энтропии физику по образованию должна быть известна. Точно так же как должны быть известны правила сложения источников белого шума, например. Всё решаемо, не надо паники. Фактически выводится на кончике пера для каждого оператора/преобразователя для конкретной разрядности и соотношения граничной интересующей частоты и частоты квантования.
Ну вот видите, как здорово. Я же не говорю, что нерешаемо. Я говорю, что надо понимать, что "чистая" математика, где все сигналы без шумов, тут неприменима. И вы это понимаете, т.к. пользуетесь специальными моделями, куда входят разрядности и частоты квантования.
V>э нет, имеется ввиду стоимость поиска внутри уже прочитанной страницы. Логическое чтени — это конечно здорово, бо внешняя память медленная. Да только ресурсов процессора практически не ест, DMA всю работу само делает. А вот проход потом по записям внутри страницы — это уже 8к надо прогнать через кеш процессора, если размер записи не будет фиксированный. А вот это уже очень даже ест разделяемые ресурсы, т.е. даже те, где логические чтения не требуются. V>Да, для некластерного указан точный адрес записи, в то время как для кластерного указан адрес диапазона с точностью до страницы. Фиксированный размер записи позволит найти запись двоичным поиском или по золотому сечению, резко уменьшив кол-во сравнений ключа с требуемым. Ну и там кеши проца и всё такое тоже играют рояль на современных многоуровневых кешах.
Отлично. Просто отлично. И вы имеете наглость утверждать, что это я не разбираюсь в практической стороне вопроса?
Поясняю по пунктам.
1. Временами сканирования страниц в ОП при подсчёте стоимости можно пренебречь. Потому что соотношение стоимостей чтения страницы с диска и из памяти чудовищно велико.
2. Размеры записей внутри страницы MS SQL не фиксированы. Независимо от наличия или отсутствия кластерного индекса. Это вы с фокспро перепутали.
Зачем вы читали исходники, если нихрена из них не поняли? Читайте лучше RTFM — там картинки есть: http://msdn.microsoft.com/en-us/library/ms190969.aspx. Цитирую:
A row offset table starts at the end of the page, and each row offset table contains one entry for each row on the page. Each entry records how far the first byte of the row is from the start of the page. The entries in the row offset table are in reverse sequence from the sequence of the rows on the page.
3. В некластерном индексе не указан "точный адрес записи". Адресация записей в странице при помощи RID — косвенная. Приходится лезть в row offset table. Это если по таблице нет кластерного индекса. А если есть, то в некластерном индексе вместо RID хранится ключ кластерного индекса, и поиск выполняется точно так же, как и для кластерного индекса.
3. Так что, никакого двоичного поиска или золотого сечения для нахождения записей внутри страницы не применяется.
Вопросы есть?
V>Пример надо модифицировать, чтобы получить разницу в страницу. Остальные соображения уже высказал в этом же посте выше.
Зачем же модифицировать? Этот пример и так ставит кластерный индекс в заведомо невыгодное положение.
V>Детсад как он есть. Как еще побочные эффекты в операциях read-only? Их нет в таких сценариях даже в самых императивных языках.
Вот именно. Пока операции read-only, никаких побочных эффектов нет, и можно выполнять эти операции в любом порядке. Или вовсе не выполнять, если не хочется.
Императивность начинается там, где появляются побочные эффекты.
V>Хе, вот только я хотел показать суть спекуляций на порядке вычисления аргументов на примере графа выражений (как выше показал твоему коллеге), ты и сам догадался. Хотя я самого начала попытался подобные спекуляции отрезать, сказав, что не интересует порядок вычисления НЕЗАВИСИМЫХ аргументов.
Ну мало ли что лично вас не интересует.
V>Хождения по кругу уровня детсада и понты, больше ничего.
Понты, коллега, в этом топике видны только от вас. И опыт-то у вас больше других, и исходники-то вы у закрытых продуктов читали, и даже одногруппник вас с полуслова понимает. А все остальные тут так, погулять вышли.
V>Хм, потеря контекста... Никакого PK на основную таблицу не требуется. Иначе не было смысла в этой избыточной. В этой таблице должны быть ровно те атрибуты, что нужны для сценария/сценариев, которые обслуживает наша избыточность. Была задача — поиметь более одного кластерного индекса, коль единственный по условию мы отдали одному из внешних ключей, как я рекомендовал. V>Это зависит от того, насколько более широкий такой "расширенный" индекс выйдет. Более широкий — более дорогой даже в выборке. Конечно, ради пары полей int32 овчинка может выделки не стоить, но я не собирался обсуждать количественные эффекты, а просто ответил на твой вопрос: "а зачем?". Надеюсь, ответил.
Да нет, пока что не ответил. Напомню: вы предположили, что неуникальный некластерный индекс — "почти всегда спорное решение", и вместо этого типа лучше иметь отдельную таблицу. Вот я и пытаюсь понять, с какого момента начинается выгода в такой "почти всегда бесспорной" архитектуре. Пока что я вижу, что вы затрудняетесь с пояснениями.
Вы не стесняйтесь — спрашивайте, если есть какие-то проблемы с пониманием архитектуры.
Вот, кстати, из новостей в MS SQL есть included columns, которые позволяют получить бенефиты кластерных индексов без применения кластерных индексов ровно в тех случаях, которые вы описываете как повод для "обыгрывания в отдельном отношении".
V>К тому же, упорядоченность кластерного индекса работает хорошо для всяких join в терминах эффективности, невыразимых в логических чтениях. Например, очень эффективно читать страницы, идущие подряд на диске, тогда нам сильно помогает кеш низлежащей ОС, со всякими новомодными технологиями, и даже сами современные диски со встроенным упреждающим чтением.
Я вижу, вы делаете несколько неявных предположений. Как обычно, демонстрируя трогательное незнакомство с предметом. Поясняю по пунктам:
1. Вы предполагаете, что страницы в кластерном индексе идут подряд на диске. Конечно же, в общем случае это не так, и механизм выделения страниц работает совершенно независимо от кластерности индекса. Если кластерный индекс вы применяете по монотонному ключу (например, это именно так для полей int identity), то механизм выделения страниц приведёт к повышению шансов на то, что соседние страницы окажутся в пределах одного экстента. В остальных случаях распределение страниц по екстентам более-менее случайно.
2. Вы предполагаете, что движок СУБД будет настолько тупым, что станет полагаться на механизмы кэширования ОС. Для случая MS SQL это, конечно же, не так. Он открывает файлы базы со специальными опциями типа FILE_FLAG_NO_BUFFERING, FILE_FLAG_OPEN_NO_RECALL, FILE_FLAG_WRITE_THROUGH, FILE_FLAG_RANDOM_ACCESS. Это чтобы дать по рукам ОС, которая захочет применить новомодные технологии кеша. Я надеюсь, вам не нужно объяснять, что делают эти флаги?
3. Конечно же, та часть движка СУБД, которая отвечает за подкачку страниц, написана не идиотами. Поэтому есть predictive reading, которому не шибко важно, в каком именно порядке идут leaf-страницы. Страницы, которые нам потребуется прочесть, ставятся в очередь, а очередь упорядочивается по адресу страницы.
S>>Откуда вы взяли трудоёмкость вставки в O(N)? Стоимость всегда логарифмическая — это же дерево. V>Дело в том, что страницы данных кластерного индекса связаны м/у собой, что позволяет перебирать их подряд при всяких join без обращения к дереву индекса.
Ну да, страницы формируют связный список. Не массив. S>>Т.е. стоимость будет стремиться к логарифмической, только если если резервировать зазоры в данных, а если не резервировать, то все данные справа от вставки придется двигать.
1. Если резервировать зазоры в данных, то вставку можно выполнить за O(1). Это понятно, почему, или нет?
2. Ок, предположим, у нас нет зарезервированных зазоров в данных. Конечно же, "все" данные справа от вставки двигать не придётся.
Мы просто разделим пополам ту страницу, на которой не хватило места, и вернёмся к коэффициенту заполнения 50%. Понятно, что сам по себе split потребует доступа к двум страницам (O(1)). Ну, и понятно, что в худшем случае нам придётся поправить O(log(N)) страниц на пути вверх к корню, чтобы отразить этот split.
Ну, то есть это как бы основы B-деревьев, но вы спрашивайте, если что-то непонятно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, vdimas, Вы писали:
V>Скорее, от отсутствия опыта по таким преобразованиям. Упомянутые алгоритмы пребирают всевозможные комбинации решений уровня РА для исходной формулы РИ. Хотя я это говорил уже не раз, видать ты подзабыл. А как затем затраты оценивают на уровне РА — мы уже прошли с самого начала. И кстати, что такое "эвристический алгоритм" — я понятия не имею.
Почитайте популярную литературу. Вот, например: http://www.slideshare.net/koolkampus/ch14. Эвристический подход к оптимизации — это систематическое применение некоторых правил преобразования, которые часто (но не всегда) дают улучшение производительности. Вы как раз приводите в своём описании набор некоторых таких правил.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Эвристический подход к оптимизации — это систематическое применение некоторых правил преобразования, которые часто (но не всегда) дают улучшение производительности. Вы как раз приводите в своём описании набор некоторых таких правил.
Суть я уловил, но мне любопытен был хоть какой-нить пример на пальцах. В голову только пока приходит предположение, что операция сравнения по какому-нить атрибуту "тяжелая", т.е. начинает заметно влиять на результат, чтобы имело смысл выполнить эти сравнения как можно позже, жертвуя взамен минимальной мощностью промежуточных результатов.
Здравствуйте, vdimas, Вы писали:
V>Суть я уловил, но мне любопытен был хоть какой-нить пример на пальцах. В голову только пока приходит предположение, что операция сравнения по какому-нить атрибуту "тяжелая", т.е. начинает заметно влиять на результат, чтобы имело смысл выполнить эти сравнения как можно позже, жертвуя взамен минимальной мощностью промежуточных результатов.
На пальцах — у нас часть предиката может соответствовать некоторому индексу, поэтому имеет смысл сначала сделать выборку по ней, а потом уже выполнять по оставшейся части.
При этом индексов может быть много, и надо выбирать, как именно резать предикат.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
V>>В вики не смотрел? V>>В общем, второе определение я оставлю лишь недобросовестным фанам функционального программирования, бо оно неверно в общем случае. S>И какое это имеет отношение к изобретённому вами определению?
Ну... попробуй как-то иначе расшифровать переход от "что" к "как", с интересом послушаю.
V>>Неодинаково. В общем случае одна операция РИ требует нескольких операций из базиса РА, обратное неверно. S>Ну начинается. Вы собрались ещё и метрику "количества операций" вводить?
Мне уровень "как" представляется как уровень с большими подробностями, относительно уровня "что". Иначе пропадает сам смысл наличия уровня "что" над "как".
S>Это всё равно заведёт вас в тупик — именно поэтому ваша идея определения декларативности не получила широкого распространения.
Идея не моя, это первоначальное значение самого слова. Я наоборот возражал против тупика (вернее — необоснованности), который начинается там, где функциональную парадигму пытаются безусловно приписать к декларативной, и ты ту же мысль здесь повторил многократно. Вот более удачное определение декларативного ЯП:
Декларати́вные языки́ программи́рования — это языки программирования высокого уровня, в которых программистом не задается пошаговый алгоритм решения задачи ("как" решить задачу), а некоторым образом описывается, "что" требуется получить в качестве результата. Механизм обработки сопоставления с образцом декларативных утверждений уже реализован в устройстве языка. Типичным примером таких языков являются языки логического программирования (языки, основанные на системе правил). В программах на языках логического программирования соответствующие действия выполняются только при наличии необходимого разрешающего условия.
Последнее выделенное противоречит утверждению о "чистых функциональных языках" в первом утверждении. Такое заметное отличие в формулировках "Декларативное программирование" и "Декларативный ЯП" лишь показывают уровень Вики, т.е. насколько этот ресурс можно использовать как аргумент (по другим твоим ссылкам).
V>>Опять же, операции базиса РА не описывают характер результата, а только лишь действия над ним. S>Да ладно! Как раз характер результата они и описывают. Скажем, оператор "сигма" никаких действий не описывает. Он просто говорит "результат будет содержать только кортежи, удовлетворяющие указанному ограничению". Что это по-вашему, как не характер результата?
Нет инвариантности использования, обязательного для декларативности, т.е. ты эти действия не можешь использовать "наоборот", например как задание для уравнения.
Основная концепция декларативной семантики заключается в том, что смысл каждого оператора не зависит от того, как этот оператор используется в программе.
Наример, любой объект пролога может быть использован как для непосредственных вычислений, так и для задания условия уравнения. Аннотация типов в статически-типизированных языках, независимо от императивности, это намного большая декларативность, чем высосанная из пальца декларативность функциональщиков в ф-ии "y x = x + 1", бо эту т.н. "декларативную ф-ию" нельзя использовать иначе как для непосредственного вычисления по ней. Эту ф-ию нельзя будет использовать как предикат, как цель или как ограничение внутри собственной программы, хотя несомненно она является целью для низлежащего механизма — компилятора, так же является декларативным ограничением для подсистемы вывода типов. Но декларативность аннотации типов работает аналогично в императивных языках, не хуже функциональных.
Для некоего низлежащего уровня реализации, перебирающего мн-во кортежей поэлементно, уровень сигмы РА будет несомненно декларативным (я на этой относительности настаиваю), бо операция РА будет задавать условие получения результата. Итого, на уровне РА операция считается "атомарной" и "безусловной", т.е. выполняемой независимо ни от чего, но на низлежащем уровне реализации некие действия над конкретными кортежами будут зависеть от истинности заданного условия.
К тому же, твоя сигма — это классический фильтр, используемый для преобразования информации, но этот фильтр на уровне РА нельзя использовать "наоборот", в кач-ве детектора, бо он описывает именно механику поэлементной фильтрации и не умеет быть детектором самостоятельно, в рамках одной операции. На уровне РИ, заметь, сигма используется как детектор.
V>>Мнэээ... Речь изначально была об O(M+N), если я ничего не пропустил. Сорри, не могу здесь поддержать твой очередной спор с самим собой. S>К счастью, в форуме записаны все ходы. "Изначально" речь шла о том, что вы почему-то заложили O(N*M*K) в стоимость операции join трёх составляющих: S>
S>Насчет порядка: если некая соединительная операция из 3-х (грубо) составляющий выполняется в 4 раза быстрее, что каждая в среднем стала выполняться быстрее в корень 3-й степени из 4.
S>Я вам тактично намекнул, что для того, чтобы это было так, нужно сочетание большого количества факторов, которые редко встречаются в жизни. Нужно, чтобы объём всех отношений был больше объёма доступных буферов, и чтобы джоин был по произвольной формуле, а не по равенству атрибутов.
Это и называется "общий случай", который правомернее любых частных. Даже когда по равенству атрибутов, но в отсутствии индексов, то сортировка (т.е. построение индексов на лету) по алгоритмам внешней сортировки для одного из аргументов даст похожую оценку сложности.
S>А для star-join с тремя составляющими стоимость будет O(N*log(M*K)).
А это при чем?
S>Так что если всё вместе выполняется в 4 раза быстрее, то каждая из операций ускорилась вовсе не в корень третьей степени из четырёх.
Тут можно вспомнить о кластерном индексе, из-за которого началось. Если мы выбираем данные не по кластерному индексу, то в общем случае каждая новая строка таблицы справа в каждом join будет требовать нового чтения всей страницы ради чтения одной записи, что приводит к немыслимому К при этих формулах. А если все строки участников физически отсортированы внутри страниц как надо для этого join, то вид формул будет совсем другой и K при них будет минимальный. Собсно, вот то предложение насчет избыточности ради дополнительных искусственных кластерных индексов я получил далеко не сразу. Была куча экспериментов на технике, на которой неоптимальное решение было видно невооруженным глазом, в отличие от сейчас.
V>>Когда речь идет о простых выборках, напр. join по основному и вненему ключу, то всё слишком очевидно, чтобы предполагать непонятно что. S>Ну, судя по вашим перлам про кластерные индексы и про оценки стоимости джойнов, очевидных вещей вообще не существует. Объяснять надо буквально каждую запятую.
Нормальная оценка джинов для боевого применения. А твои "более реальные условия" — это фактически минибазульки, а не "реальные условия". Для реляционных СУБД всегда надо исходить из данных, больших ОП, иначе стоит подумать о другой технологии.
S>Многие приложения, построенные по принципу select N+1 и client-side join, прекрасно работают на встроенных движках, и даже на тупом ISAM. S>И, естественно, со страшной силой начинают сливать при переходе на клиент-серверную архитектуру, потому что там это честный roundtrip с парсингом и исполнением каждого запроса. Поэтому всякий раз, как я вижу упоминание тормозов при переходе с фокспра на оракл или с аксесса на MSSQL, я начинаю подозревать худшее.
Я че-то не понял объяснения, почему клиентский движок может выполнить select N+1 быстрее серверного? За счет чего именно? К тому же, тормоза были не там, а из-за многократно большего требования к размеру ОП (физическое уменьшение размера данных помогло) и чувствительности к организации кластерных индексов. И к тому же, SQL выдает первые данные раньше, чем закончивает полную выборку, т.е. по мере готовности, при чем тут roundtrip? Или неужели клиентский движок парсит запросы быстрее? А если это не текстовые запросы, а вызов процедур или view?
S>Но это, естественно, не единственное объяснение. Понятно, что, скажем, в линейном чтении с локального диска любой dBase порвёт любой сиквел как тузик грелку. Поэтому я и написал, что не могу делать выводы о вашем опыте, не глядя в исходники приложения.
Это бы еще куда ни шло... Неприятно, что технологии локальных движков рвут SQL-сервера, даже когда первые работали по сетевому диску до этого. И кстати, ORACLE тех времен смотрелся всяко получше MS SQL в отклике, хотя последний гораздо проще в обслуживании и программировании.
V>>Пока что согласился только насчет оценок быстродействия кластерного индекса, и то, там бабка на двое сказала. Бо даже лишняя страница по тем временам на том размере ОП (т.е. не та политика кеширования была), с теми скоростями жестки дисков и т.д., могла и дать такую ощутимую разницу. S>Да-да, разницу в "десять-пятнадцать страниц". Я понял. Но я же говорю не о том, что ваш конкретный проект работал как-то не так. Я говорю ровно про то, что ваш подход к исследованию мира даёт вот такие вот результаты: вы увидели некий эффект, и вместо того, чтобы разобраться, поставили кластерные индексы на полочку "тормозное г".
Нет, было сказано, что для первичных ключей они оказались в большинстве сценариев нехороши. Справедливости ради, для справочных данных кластерные индексы для основного ключа таки хороши (это очевидно). Так же хороши везде для основных ключей, где сами таблицы невелики (влазят в единицы 1-2 физических страниц), независимо от сценариев, это тоже утверждалось. К тому же, ты пытаешься сфокусировать спор на сценарии выбора одной строки и сам же допускаешь одно лишнее логическое чтение на такую выборку. Где-нить в середине join это запросто может быть по лишней логической выборке на каждую включенную строку. Что на малой возможности буферирования из-за размеров ОП могло превращать приличную долю логических чтений в тормознутые физические на тех винтах с 30-50ms seek. Ты просто не понял, что я имел ввиду насчет сложности воспроизведения эффекта на современных машинах. Хотя, это зависит лишь от масштабов.
S>С тех пор и память стала другая, и диски несколько другие, но ментальная модель кластерных индексов в вашей голове изменений не претерпела — потому, что там монолит. Нет границы между архитектурой кластерных индексов и её реализацией.
Я лишь вижу, что те сценарии, которые я рассматривал как "очень некоторые", ты рассматриваешь как "почти все"...
Ес-но, отсюда разный взгляд на вещи.
V>>Боюсь, на современных ОС и современном железе воспроизвести сей эффект будет сложновато. S>Боюсь, вы по-прежнему не понимаете предмета обсуждения. Количество логических чтений в MS SQL никак не зависит ни от ОС, ни от железа.
Эффект был не в логических чтениях, а в абсолютном быстродействии. Самая тяжеловесная операция, где всё вылизывалось — это полный перерасчет операционного дня. Много join, и в ширь и в глубь. Лишние прочитанные страницы на каждую строку где-нить в глубине join могли оказаться фатальными. Действительно заметно помогли вот те "искуственные индексы", т.е. банальная избыточность, где по каждой такой избыточности построен кластерный индекс именно под конкретный сценарий, чтобы к дереву индекса практически не обращались, а шел перебор связанного списка страниц.
Кстати, еще момент. В конечном итоге пришел к по-позиционному расчету в цикле. Почему в цикле, а не в виде одного запроса? В виде единого запроса работало в несколько раз медленней даже после всех игр с уровнями блокировок и даже с хинтами без блокировок вообще (что было недопустимо, но гонялось для экспериментов). К тому же, торможение единого запроса фактически не давало работать остальным, пока выполнялся запрос, а по-позиционный расчет в этом плане был более "легок" для базы, позволял работать остальным... и сам выполнялся в итоге быстрее! Т.е. сотни транзакций выполнялись быстрее одной транзакции. Тоже есть о чем подумать... Всего навсего в тот же самый запрос добавили ограничение на одну позицию и прогнали по всем задействованным за день позициям в цикле. Подозреваю, что тоже дело было в объемах промежуточных данных, что болезненно.
S>Всё правильно. Вот только я никаких противоречий и не декларировал. Я объяснял, что одних законов РА недостаточно для функционирования реальных СУБД.
Ты утверждал, что им нет места. Более всего категорично при выборе, какой индекс использовать для физического плана и как. Я потому и зацепился, что аж стало интересно — а какой же теоретический аппарат тогда используют???
S>И что нужно понимать, где начинаются "дополнительные подробности". Иначе можно запросто попасть впросак, написав бред типа "стоимость операции join пропорциональна O(N*M)".
Для декартового произведения это так по-определению. Другое дело, что ты сложность считаешь исключительно в логических чтениях, считая, что порождение результата затем бесплатно. А оно зависит от много чего, т.е. чтение является лишь частью от всей сложности. Ведь не читает же SQL Server с диска медленнее, чем локальный движок базы данных? Скорее, наоборот, бо его поставили на гораздо более мощную технику. Т.е. тормоза не только на чтении данных. Далее. Для несортированных N и M в пределе сложность можно считать близкой к такой, из-за стоимости алгоритмов внешней сортировки при построении индекса "на лету", и из-за более дорогой записи в сравнении с чтением. Понятно, что коль индекс строится не по всем полям, а лишь по части, то мы можем получить оч. низкий К при этой оценке, но сама полная сложность в пределе именно такова.
Ну и "реальные размеры реальных буферов" оставь, плиз, для своих собственных сценариев, бо я плохо представляю что делать с аргументами, с которыми сам сталкивался нечасто. Возьми современные биржи — трафик до нескольких тысяч транзакций в секунду в пиковые часы. Какие нафик "буфера в памяти", когда делаешь к ней запросы по своим транзакциям за день? А за неделю? Там такие кластера, что мама не горюй, и все-равно итоговые запросы выполняются секунды, а не миллисекунды.
V>>Потому и напомнил. Что различия реализации и модели есть, а для 99% сценариев не помеха. А где помеха — там есть совсем простые паттерны обхода ограничения реализации. S>В программировании все помехи — исключительно в голове. Именно поэтому так важно хорошо во всём разбираться.
Угу, возвращаемся к самому началу. "Хорошо" — означает подробно? Означает знать как все устроено или хотя бы как устроено аналогичное или таки неважно?
V>>И я показал, что таки не очень мешает. И оценка в 1% от таких сценариев — это еще очень оптимистично, бо я с переполнениями борюсь даже далеко не в каждом проекте, где многие тысячи целочисленных переменных. S>Ну я рад за ваши проекты. Это всего лишь означает, что ваши программы — некорректны, просто вас не везде поймали за руку ваши QA.
Нет, это означает, что были взяты нужные типы данных для нужных платформ. Это в C# интерфейсы коллекций завязали на платформенно-независимый int, что есть большая грабля сама по себе, а в С++ используется платформенно-зависимый тип size_t. И вообще, беззнаковая арифметика в почете, бо позволяет делать на одно сравнение меньше для выяснения соответствия требуемому диапазону.
S>И, кстати, из двух предоженных вами решений проблемы с переполнением при построении компаратора одно не работает.
Оно даже не компилируется, если ты про приведение к Int64... писал поздно и быстро. Ожидал сие возражение там же сразу, оно было очевидным после отправки без предварительного просмотра... Вы бы уже что-нить сделали с сайтом, чтобы на Хроме предпросмотром можно было пользоваться... А то столько умных рассуждений, пока дело до дела не доходит.
V>>Ну-ну, не разгоняйся так быстро. Я такими аппаратами пользуюсь, что поверь, придумать их самому, специально под реализации вещественных чисел — ну просто никак. Например, в области обнаружения и обработки сигналов. Всего навсего погрешности округлений представляют как аддитивный шум, поэтому всё несоответствие реализации и модели сводится к оценке шума (тем более достоверно известен его спектральный состав), т.е. к достижению требуемого отношения сигнал/шум. И для этого тоже аппарат есть — "энтропийный": H + Y = 1 (Взаимосвязь энтропии и информации). А формула самой энтропии физику по образованию должна быть известна. Точно так же как должны быть известны правила сложения источников белого шума, например. Всё решаемо, не надо паники. Фактически выводится на кончике пера для каждого оператора/преобразователя для конкретной разрядности и соотношения граничной интересующей частоты и частоты квантования. S>Ну вот видите, как здорово. Я же не говорю, что нерешаемо. Я говорю, что надо понимать, что "чистая" математика, где все сигналы без шумов, тут неприменима. И вы это понимаете, т.к. пользуетесь специальными моделями, куда входят разрядности и частоты квантования.
Нет, применима. Математика — это уже модель сама по себе, она не существует как объективная реальность. Более того, это ср-во построения моделей. Какую захотим построить модель, такую и построим. (вернее, которая подойдет — такую и пользуем). Где отношение сигнал-шум не так уж важно, а важна лишь вероятность срабатывания, например, (распознавание DTMF, например), то там вообще погрешность вычислений может доходить до 75% (свертка с прямоугольным сигналом, т.е. выполнение простых +- вместо сложения ряда, умноженного на отсчеты синусоиды). Но этого оказалось достаточно для нужной вероятности обнаружения сигнала, бо сам алгоритм такой, что работает даже тогда, когда сигнал в 4 раза меньшей мощности, чем белый фоновый шум. Вот тебе объективный случай, когда заведомо грубая реализация математической модели с погрешностью до 75% вполне подходит, потому что удовлетворяет требованиям алгоритма. Потому что после фильтрации почти равномерный спектральный состав мощности шума этой погрешности оказывается крайне незначительным в нужной полосе.
Здравствуйте, vdimas, Вы писали: V>Мне уровень "как" представляется как уровень с большими подробностями, относительно уровня "что". Иначе пропадает сам смысл наличия уровня "что" над "как".
Это достаточно наивное представление, равно как и попытки располагать "что" над "как". В связи с теоремой Чёрча, бывает всякое — в том числе, и описание "как", более компактное, чем "что".
V>Идея не моя, это первоначальное значение самого слова.
Ну щас прямо.
V>Последнее выделенное противоречит утверждению о "чистых функциональных языках" в первом утверждении. Такое заметное отличие в формулировках "Декларативное программирование" и "Декларативный ЯП" лишь показывают уровень Вики, т.е. насколько этот ресурс можно использовать как аргумент (по другим твоим ссылкам).
V>>>Опять же, операции базиса РА не описывают характер результата, а только лишь действия над ним. S>>Да ладно! Как раз характер результата они и описывают. Скажем, оператор "сигма" никаких действий не описывает. Он просто говорит "результат будет содержать только кортежи, удовлетворяющие указанному ограничению". Что это по-вашему, как не характер результата?
V>Нет инвариантности использования, обязательного для декларативности, т.е. ты эти действия не можешь использовать "наоборот", например как задание для уравнения. V>
V>Основная концепция декларативной семантики заключается в том, что смысл каждого оператора не зависит от того, как этот оператор используется в программе.
Вы очень ловко одной рукой критикуете википедию, а другой тут же ссылаетесь на неё же. Статья, на которую вы ссылаетесь, это всего лишь заглушка, в которой написано несколько бессмысленных фраз. Перейдите в англоязычную версию — там очень внятно написано, что такое декларативное программирование и чем оно отличается от императивного.
Никакой "основной концепции" там, естественно, нет.
V>Для некоего низлежащего уровня реализации, перебирающего мн-во кортежей поэлементно, уровень сигмы РА будет несомненно декларативным (я на этой относительности настаиваю), бо операция РА будет задавать условие получения результата.
Ну вот видите. Всё-таки декларативна.
V>К тому же, твоя сигма — это классический фильтр, используемый для преобразования информации, но этот фильтр на уровне РА нельзя использовать "наоборот", в кач-ве детектора, бо он описывает именно механику поэлементной фильтрации и не умеет быть детектором самостоятельно, в рамках одной операции. На уровне РИ, заметь, сигма используется как детектор.
А можно пояснить подробнее, что значит "использовать наоборот"?
S>>Я вам тактично намекнул, что для того, чтобы это было так, нужно сочетание большого количества факторов, которые редко встречаются в жизни. Нужно, чтобы объём всех отношений был больше объёма доступных буферов, и чтобы джоин был по произвольной формуле, а не по равенству атрибутов.
V>Это и называется "общий случай", который правомернее любых частных.
Для оценки сложности нет "общего случая". Чему равна сложность квиксорт для "общего случая", по-вашему?
V>Даже когда по равенству атрибутов, но в отсутствии индексов, то сортировка (т.е. построение индексов на лету) по алгоритмам внешней сортировки для одного из аргументов даст похожую оценку сложности.
Непохожую. Учите матчасть.
V>Тут можно вспомнить о кластерном индексе, из-за которого началось. Если мы выбираем данные не по кластерному индексу, то в общем случае каждая новая строка таблицы справа в каждом join будет требовать нового чтения всей страницы ради чтения одной записи, что приводит к немыслимому К при этих формулах.
При каких формулах? Мы говорим о K при логарифме, и ничего немыслимого в нём нет. В любом случае это не K при N, как вам кажется.
V>Нормальная оценка джинов для боевого применения. А твои "более реальные условия" — это фактически минибазульки, а не "реальные условия".
Вы не читаете то, что я вам пишу. Дело не в размере базы, а в том, какие индексы применяются. Получение O(N*M) на джойне по равенству атрибутов, при произвольном размере базы — это признак кривых рук у DBA.
V>Я че-то не понял объяснения, почему клиентский движок может выполнить select N+1 быстрее серверного? За счет чего именно?
За счёт того, вестимо, что все данные для него локальны, зачастую еще и лежат прямо в ОП, а транзакции — это условность. Поэтому ему всё равно, что выполнять — один селект на 100 записей или 100 селектов по одной записи. А для честного сервера, который принимает запросы по сети, 100 селектов по одной записи сильно хуже, чем один селект на 100 записей. Ваш К.О.
V>Нет, было сказано, что для первичных ключей они оказались в большинстве сценариев нехороши. Справедливости ради, для справочных данных кластерные индексы для основного ключа таки хороши (это очевидно). Так же хороши везде для основных ключей, где сами таблицы невелики (влазят в единицы 1-2 физических страниц), независимо от сценариев, это тоже утверждалось. К тому же, ты пытаешься сфокусировать спор на сценарии выбора одной строки и сам же допускаешь одно лишнее логическое чтение на такую выборку. Где-нить в середине join это запросто может быть по лишней логической выборке на каждую включенную строку.
То, что я фокусируюсь на сценарии выбора одной строки — это я вам одолжение делаю. В сценариях с join кластерный индекс порвёт некластерный вообще в мелкие ошмётки. Ну и, опять же, ваше утверждение было именно про выборку одного значения.
V>Я лишь вижу, что те сценарии, которые я рассматривал как "очень некоторые", ты рассматриваешь как "почти все"...
Я привёл свои соображения про то, какие факторы влияют на выбор кластерных/некластерных индексов. Вы подняли их на смех, не дав труда задуматься, какие случаи — "почти все", а какие — "очень некоторые". V>Ес-но, отсюда разный взгляд на вещи.
Разный взгляд на вещи у нас оттого, что я понимаю, как устроены кластерные индексы, и как работает движок в MS SQL, а вы — нет.
V>Эффект был не в логических чтениях, а в абсолютном быстродействии. Самая тяжеловесная операция, где всё вылизывалось — это полный перерасчет операционного дня. Много join, и в ширь и в глубь. Лишние прочитанные страницы на каждую строку где-нить в глубине join могли оказаться фатальными. Действительно заметно помогли вот те "искуственные индексы", т.е. банальная избыточность, где по каждой такой избыточности построен кластерный индекс именно под конкретный сценарий, чтобы к дереву индекса практически не обращались, а шел перебор связанного списка страниц.
Ой, как интересно. А в прошлый раз вы рассказывали ровно наоборот — вы заменяли кластерные индексы на некластерные, и сокращали размер ключа с 4х байт до 2х.
Видите, как заметно меняется прошлое, стоит разобраться в вопросе, да?
V>Подозреваю, что тоже дело было в объемах промежуточных данных, что болезненно.
А не надо подозревать. Надо пользоваться SQL Profiler и вдумчиво читать документацию. Ваши подозрения приводят к чудовищным заблуждениям.
S>>Всё правильно. Вот только я никаких противоречий и не декларировал. Я объяснял, что одних законов РА недостаточно для функционирования реальных СУБД.
V>Ты утверждал, что им нет места. Более всего категорично при выборе, какой индекс использовать для физического плана и как. Я потому и зацепился, что аж стало интересно — а какой же теоретический аппарат тогда используют???
Оценки размеров результатов запросов — распределение Зипфа; информацию о статистиках; семантическую информацию (например, наличие constraints). Именно это и используют. А с точки зрения РА все планы запросов одинаковы. Выбрать ничего не получится.
S>>И что нужно понимать, где начинаются "дополнительные подробности". Иначе можно запросто попасть впросак, написав бред типа "стоимость операции join пропорциональна O(N*M)".
V>Для декартового произведения это так по-определению.
Ну так join — это не декартово произведение. Ваш К.О.
V>Другое дело, что ты сложность считаешь исключительно в логических чтениях, считая, что порождение результата затем бесплатно. А оно зависит от много чего, т.е. чтение является лишь частью от всей сложности. Ведь не читает же SQL Server с диска медленнее, чем локальный движок базы данных?
Конечно же читает медленнее. У него архитектура движка другая. Учите матчасть. Для того, чтобы приблизиться к скорости чтения ФС, движок MS SQL пришлось сильно переработать. RTFM по слову FILESTREAM. ISAM-движки при линейном чтении приближаются к скорости чистого чтения с ФС.
V>Скорее, наоборот, бо его поставили на гораздо более мощную технику. Т.е. тормоза не только на чтении данных. Далее. Для несортированных N и M в пределе сложность можно считать близкой к такой, из-за стоимости алгоритмов внешней сортировки при построении индекса "на лету", и из-за более дорогой записи в сравнении с чтением. V>Понятно, что коль индекс строится не по всем полям, а лишь по части, то мы можем получить оч. низкий К при этой оценке, но сама полная сложность в пределе именно такова.
Ок, давайте оценим стоимость построения индекса "на лету" и посмотрим, какая получится оценка. Если вам лень — подсмотрите в учебнике. Я чувствую, вас ждёт неожиданное открытие.
S>>В программировании все помехи — исключительно в голове. Именно поэтому так важно хорошо во всём разбираться. V>Угу, возвращаемся к самому началу. "Хорошо" — означает подробно? Означает знать как все устроено или хотя бы как устроено аналогичное или таки неважно?
Конечно. Чем лучше разбираешься — тем лучше. Но тут важен такой момент: знать всё — нереально. Поэтому важно эффективно применять те знания, которые уже есть. И вот тут очень важно понимать границы применимости того или иного.
V>Нет, это означает, что были взяты нужные типы данных для нужных платформ. Это в C# интерфейсы коллекций завязали на платформенно-независимый int, что есть большая грабля сама по себе, а в С++ используется платформенно-зависимый тип size_t. И вообще, беззнаковая арифметика в почете, бо позволяет делать на одно сравнение меньше для выяснения соответствия требуемому диапазону.
Ок, не будем копать в эту сторону.
V>Оно даже не компилируется, если ты про приведение к Int64... писал поздно и быстро. Ожидал сие возражение там же сразу, оно было очевидным после отправки без предварительного просмотра...
Даже если бы компилировалось — там сам подход неверен.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
V>>Мне уровень "как" представляется как уровень с большими подробностями, относительно уровня "что". Иначе пропадает сам смысл наличия уровня "что" над "как". S>Это достаточно наивное представление, равно как и попытки располагать "что" над "как".
"Что" и "как" — это вполне интуитивные понятия, имеющие однозначную языковую семантику, а вовсе не наивные. Тебя че-то несет не в ту степь. Так нам придется предварительно договариваться о смысле слов, из которых будут состоять наши посты... правда я не знаю, в каком алфавите...
S>В связи с теоремой Чёрча, бывает всякое — в том числе, и описание "как", более компактное, чем "что".
Есть такая теорема, которая прямо определяет где у неё "что", а где "как"? Или ты как обычно решил подменить слово "декларативный" на "функциональный"?
V>>Идея не моя, это первоначальное значение самого слова. S>Ну щас прямо.
Т.е. таки разногласия в понимании взаимоотношений понятий "как" и "что"?
V>>Нет инвариантности использования, обязательного для декларативности, т.е. ты эти действия не можешь использовать "наоборот", например как задание для уравнения. V>>
V>>Основная концепция декларативной семантики заключается в том, что смысл каждого оператора не зависит от того, как этот оператор используется в программе.
S>Вы очень ловко одной рукой критикуете википедию, а другой тут же ссылаетесь на неё же. Статья, на которую вы ссылаетесь, это всего лишь заглушка, в которой написано несколько бессмысленных фраз. Перейдите в англоязычную версию — там очень внятно написано, что такое декларативное программирование и чем оно отличается от императивного.
Ты утверждал, что иммутабельное означает декларативное. У меня сразу куча вопросов. А если у нас иммутабельность не накладывается за счет ср-в языка, а выходит "по факту", только потому что алгоритм, например, никогда не заешл в ветку для мутабельности неких данных?.. или же эта ветка и не была написана, но программа целиком на императивном языке?.. я постоянно вижу у молодых и неокрепших умов, что их сама практика эта программирования — иммутабельность — зачастую сбивает с толку. Это всего-лишь паттерн. Одна из многих наработок.
S>Никакой "основной концепции" там, естественно, нет.
Знака равенства м/у ортогональными понятиями тоже нет. Да и видел я твои ссылки на английскую википедию по РА — большей путаницы, недосказанности, отсутствия последовательности и прочей каши еще поискать. Писатели-любители составляли, через поиск по гуглу, а не специалисты в описываемой области.
V>>Для некоего низлежащего уровня реализации, перебирающего мн-во кортежей поэлементно, уровень сигмы РА будет несомненно декларативным (я на этой относительности настаиваю), бо операция РА будет задавать условие получения результата. S>Ну вот видите. Всё-таки декларативна.
printf("%d", x); — точно так же декларативен для некоей низлежащей системы, как и сигма. Эти спекуляции ведут в никуда, ведь ты сначала отвергаешь взаимоотношение РИ и РА как уровней с разными степенями подробностей, а потом пытаешься исопльзовать еще более низкий уровень как некое док-во декларативности более высокого по-отношению к нему. Не выйдет. Мы способов реализации формул РА не обсуждали и не будем.
V>>К тому же, твоя сигма — это классический фильтр, используемый для преобразования информации, но этот фильтр на уровне РА нельзя использовать "наоборот", в кач-ве детектора, бо он описывает именно механику поэлементной фильтрации и не умеет быть детектором самостоятельно, в рамках одной операции. На уровне РИ, заметь, сигма используется как детектор. S>А можно пояснить подробнее, что значит "использовать наоборот"?
Чем фильтрация сигнала от обнаружения отличается? Тем, что фильтрация в общем случае налагает лишь некоторые ограничения, которыми должен обладать сигнал, но реальная конструкция сигнала может быть гораздо сложнее, чем возможно выделить одним фильтром или даже несколькими фильтрами, т.к. кодирование информации может случается разное, она может быть закодирована как статические или даже динамические х-ки, получаемые сразу по многим фильтрам. Поэтому каждый фильтр "просто делает своё дело", не подозревая, как будут использоваться результаты его труда. Например, все структурные формулы РИ приводимы к одному квантору EXISTS, который использует сигму как детектор по своему определению, но после перевода конкретного квантора EXISTS в формулу РА, состоящую из продукций, проекций и ограничений, ты не можешь по каждой отдельной выделенной операции судить, какой же был вид исходного (целевого) квантора. Т.е. в каждом отдельном операторе РА непонятно, как же было сформулировано "что" в исходном операторе РИ.
V>>Тут можно вспомнить о кластерном индексе, из-за которого началось. Если мы выбираем данные не по кластерному индексу, то в общем случае каждая новая строка таблицы справа в каждом join будет требовать нового чтения всей страницы ради чтения одной записи, что приводит к немыслимому К при этих формулах. S>При каких формулах? Мы говорим о K при логарифме, и ничего немыслимого в нём нет. В любом случае это не K при N, как вам кажется.
Эта К будет при каждой операции чтения, т.е. при N, независимо от затрат на обход индекса. Эти логарифмические затраты просто не видны обычно на фоне чтения страниц "вразнобой".
V>>Нормальная оценка джинов для боевого применения. А твои "более реальные условия" — это фактически минибазульки, а не "реальные условия". S>Вы не читаете то, что я вам пишу. Дело не в размере базы, а в том, какие индексы применяются. Получение O(N*M) на джойне по равенству атрибутов, при произвольном размере базы — это признак кривых рук у DBA.
Еще раз, эта сложность у операции декартова произведения по-определению. Я знаю, что ты настаиваешь на оценке исключительно логического чтения. Но, логические не значат физические и не только на чтение с диска нужны ресурсы. Даже начинающие программисты замечают, что многие простые запросы по большому кол-ву данных выполняются быстрее некоторых других сложных запросов по относительно небольшому кол-ву данных, даже со всеми индексами в нужном порядке. Более того, на чтение физическое чтение как раз ресурсы проца нужны не особо, DMA всё само делает, т.е. проц в многозадачной ОС (и СУБД сверху неё) способен нести в этой время какую-нить другую нагрузку.
V>>Я че-то не понял объяснения, почему клиентский движок может выполнить select N+1 быстрее серверного? За счет чего именно? S>За счёт того, вестимо, что все данные для него локальны, зачастую еще и лежат прямо в ОП, а транзакции — это условность. Поэтому ему всё равно, что выполнять — один селект на 100 записей или 100 селектов по одной записи. А для честного сервера, который принимает запросы по сети, 100 селектов по одной записи сильно хуже, чем один селект на 100 записей. Ваш К.О.
Фи, как низкопробно. Т.е. ты считаешь, что основная лишняя нагрузка на СУБД — это работа по обслуживанию запросов, передачи по сети каждый раз заново заголовков таблиц вместе с данными и т.д.?
Тогда действительно, относительные тормоза SQL-серверов проявлялись бы там, где размер служебной передаваемой информации превышает полезную. Ну и еще вспомним, что по named-pipes народ не часто подключает MS SQL, а про работу нагиля в TCP забывает и не конфигурит TCP-соединение, чтобы нагиль не мешал, и не умеет выполнить более 5-ти запросов в секунду на одном соединении... и потом рассуждают на таком печальном уровне о roundtrip-ах. Кароч, это всё детский сад, а не объяснение. MS SQL сливает даже там, где требуются просто тяжеловесные вычисления по сложному запросу, а не "куча мелких запросов". ИМХО от того, что локальные базы агрессивно юзают маппинг файлов и более эффективно (в плане обработки) располагают свои данные. По крайней мере, не надо читать конец страницы, чтобы пройтись бинарным поиском по данным. Попробуй ради прикола нарисуй на C++ программу, которая будет перебирать строки внутри страницы по смещению, указанному в конце страницы, как ты показал для MS SQL, то бишь использовать банально +1 косвенности к адресации... Да это пипец полный для пробежки по данным, таким макаром. И ко всему прочему добавляется копирование в отдельный участок памяти целой страницы и обратно, даже если нам надо изменить всего байт...
S>То, что я фокусируюсь на сценарии выбора одной строки — это я вам одолжение делаю. В сценариях с join кластерный индекс порвёт некластерный вообще в мелкие ошмётки.
И как он порвет, если редко бывает так, что по одной таблице выполняется join только по одному и тому же индексу? Кластерный же один только. Т.е. для одного сценария порвет, а другие сольют.
S>Ну и, опять же, ваше утверждение было именно про выборку одного значения.
Ну и ты сам увидел на лишнее чтение на строку. Поэтому если делается join не по кластерному, то имеем лишнее логическое чтение на каждую строку.
V>>Я лишь вижу, что те сценарии, которые я рассматривал как "очень некоторые", ты рассматриваешь как "почти все"... S>Я привёл свои соображения про то, какие факторы влияют на выбор кластерных/некластерных индексов. Вы подняли их на смех, не дав труда задуматься, какие случаи — "почти все", а какие — "очень некоторые".
ИМХО, случай, когда для некоей таблицы во всех сценариях выборки, происходящих вокруг нее встречается только один вид join, это таки "очень некоторые".
V>>Ес-но, отсюда разный взгляд на вещи. S>Разный взгляд на вещи у нас оттого, что я понимаю, как устроены кластерные индексы, и как работает движок в MS SQL, а вы — нет.
Я рассказал о внешних эффектах, которые были обнаружены и обкатаны многократно во всех вариантах. Стоит вернуться и попытаться соотнести свое представление о кишках этой СУБД и причин производимых ими эффектов.
V>>Эффект был не в логических чтениях, а в абсолютном быстродействии. Самая тяжеловесная операция, где всё вылизывалось — это полный перерасчет операционного дня. Много join, и в ширь и в глубь. Лишние прочитанные страницы на каждую строку где-нить в глубине join могли оказаться фатальными. Действительно заметно помогли вот те "искуственные индексы", т.е. банальная избыточность, где по каждой такой избыточности построен кластерный индекс именно под конкретный сценарий, чтобы к дереву индекса практически не обращались, а шел перебор связанного списка страниц.
S>Ой, как интересно. А в прошлый раз вы рассказывали ровно наоборот — вы заменяли кластерные индексы на некластерные, и сокращали размер ключа с 4х байт до 2х. S>Видите, как заметно меняется прошлое, стоит разобраться в вопросе, да?
Я упоминал каждый из способов, который давал прибавки к эффективности, многократно. Нигде ничего не меняется. Да, заменял кластерные индексы по уникальному ключу на некластерные, а кластерные оставлял для неуникальных (внешних, например, или индексов для поиска). На самом деле местами шел просто тупой перебор всех возможных вариантов индексов и тщательные замеры. Конкретные цифры помнить не могу, но отличие получившихся решений от первоначальных озвучил многократно.
V>>Подозреваю, что тоже дело было в объемах промежуточных данных, что болезненно. S>А не надо подозревать. Надо пользоваться SQL Profiler и вдумчиво читать документацию. Ваши подозрения приводят к чудовищным заблуждениям.
Гы, профайлер от 7-ки и был основным инструментом. Только он не объяснит, почему несколько транзакций в процедуре в цикле с доп. условием к запросу дешевле одной транзакции без условий. Показал он тебе больше промахов кеша, дальше что? Проведя несколько построчных запросов тоже кеш смениться многократно... Просто было интересно следующее: почему надо делать искусственный построчный прогон для уменьшения промахов кеша, если он должен нечто аналогичное делать сам? Ну и, конечно, сам факт работы одновременно других людей с базой вносит свои коррективы, для более короткой транзакции зачистка кеша каким-нить конкурирующим запросом не так болезненна. Да и размер изолированных данных и всяких их реплик начинает играть рояль... Это я все пишу насчет того, что измерять производительность теоретически, одними только логическими чтениями, фактически бесполезно в реальных условиях. Твой подход работает только там, где остальными описанными факторами можно пренебречь, например, когда имеем многократный запас в производительности и памяти относительно окучиваемых задач.
Ну и конфигурация самого сервака — это было нечто...сейчас толком никто не парится, оставляют значения по умолчанию. Например, чего стоил один только ключ располагать временные таблицы в памяти. В зависимости от сценариев это могло как добавить резко эффективности, так и наоборот.
Ну и во всех гайдлайнах настоятельно MS советует отделять оперативные данные от исторических первой строчкой рекомендаций. Причем, и даже разносить их по разным серверам. Дык, а в твоей системе координат, коль речь идет о разных таблицах, какая фиг разница, не правда ли? Ведь количество логических чтений независимо для независимых запросов...
В общем, картинка ясна. Упоминая зачем-то термин "промышленные СУБД", ты, тем не менее, не особо сталкивался с "промышленными" соотношениями объемов данных, уровня конкурентности соединений и возможностей техники. Да еще небось база работает в тепличных условиях трехзвенки, коль идут нелепые рассуждения о roundtrip... нелепые для случая, когда >90% логики программы выполняется внутри SQL-сервера, т.е. когда у нас почти всегда один запрос и один ответ, даже если сервер в ответ возвращает последовательность из сотни различных рекордсетов. В общем, мне сложно работать К.О. для сценариев, которых не видел... приводить как аргумент сценарии из 100 коротких запросов к СУБД, которая работает как отдельный процесс или как отдельная машина — это рассуждения о кривизне рук, более ни о чем...
V>>Ты утверждал, что им нет места. Более всего категорично при выборе, какой индекс использовать для физического плана и как. Я потому и зацепился, что аж стало интересно — а какой же теоретический аппарат тогда используют??? S>Оценки размеров результатов запросов — распределение Зипфа; информацию о статистиках; семантическую информацию (например, наличие constraints). Именно это и используют. А с точки зрения РА все планы запросов одинаковы. Выбрать ничего не получится.
Какая разница, как конкретно устроена оценочная ф-ия? Чем дальше, тем больше будет методик составления сей оценочной ф-ии и способов представления статистики для нее. Мы уже давно договорились, что ее вид f(x1, x2, x3, ...), т.е. обычный черный ящик. Я утверждал, что породить всевозможные комбинации последовательностей операций для последующей оценки весовой ф-ией можно как раз с помощью аппарата РА. Вот это ты и отрицаешь до сих пор, и я хочу таки услышать, какой для этого исопльзуется аппарат. Мне плевать на конкретную оценочню ф-ю, расскажи, как строиться и модифицируется план запросов, который потом оценивается. Ты спорил лишь потому, что не считаешь индексы за декомпозицию исходной таблицы и всё еще продолжаешь рядом приводить нелепые примеры, подтверждая свое непонимание происходящего:
V>Суть я уловил, но мне любопытен был хоть какой-нить пример на пальцах. В голову только пока приходит предположение, что операция сравнения по какому-нить атрибуту "тяжелая", т.е. начинает заметно влиять на результат, чтобы имело смысл выполнить эти сравнения как можно позже, жертвуя взамен минимальной мощностью промежуточных результатов.
На пальцах — у нас часть предиката может соответствовать некоторому индексу, поэтому имеет смысл сначала сделать выборку по ней, а потом уже выполнять по оставшейся части.
При этом индексов может быть много, и надо выбирать, как именно резать предикат.
Такого рода ответы уже просто лень комментировать. Ведь это и есть тот самый перебор вариантов формул РА. Я фиг его знает почему ты решил, что для этих вещей исопльзуется какая-то особая, недоступная простым смертным, технология... Хотя в деле организации индексов мало что поменялось с выхода первых СУБД.
S>>>И что нужно понимать, где начинаются "дополнительные подробности". Иначе можно запросто попасть впросак, написав бред типа "стоимость операции join пропорциональна O(N*M)".
V>>Для декартового произведения это так по-определению. S>Ну так join — это не декартово произведение. Ваш К.О.
Это смотря какой join и как организованы данные.
V>>Другое дело, что ты сложность считаешь исключительно в логических чтениях, считая, что порождение результата затем бесплатно. А оно зависит от много чего, т.е. чтение является лишь частью от всей сложности. Ведь не читает же SQL Server с диска медленнее, чем локальный движок базы данных? S>Конечно же читает медленнее. У него архитектура движка другая. Учите матчасть. Для того, чтобы приблизиться к скорости чтения ФС, движок MS SQL пришлось сильно переработать. RTFM по слову FILESTREAM. ISAM-движки при линейном чтении приближаются к скорости чистого чтения с ФС.
Какой нах FILESTREAM, когда речь идет о страницах с обычными данными? Насчет "приближаются к скорости чистого чтения" — это иди учи матчасть сам... Не приближаются, а в точности равны, бо работают через memory-mapped file. Дело, конечно, в неумении автоматически детектить моменты, когда требуется конкурентность, от моментов, когда не особо требуется. Это я намекаю, что уровней изоляции во встроенных движках обычно поменьше, а сценарий простой полной блокировки очень дешевы в условиях малого кол-ва одновременных запросов, но когда сами запросы относительно тяжелы. Но MS SQL, похоже, всегда создает копии страниц в ОП (хотя сами страницы, скорее всего читает так же через memory-mapped file), и работает уже с ними... ИМХО, если стоимость запроса была известна заранее, то вполне мог бы быть некий "порог" конкурентности для конкретной таблицы или целого файла данных, чтобы работать с данными по месту.
V>>Понятно, что коль индекс строится не по всем полям, а лишь по части, то мы можем получить оч. низкий К при этой оценке, но сама полная сложность в пределе именно такова. S>Ок, давайте оценим стоимость построения индекса "на лету" и посмотрим, какая получится оценка. Если вам лень — подсмотрите в учебнике. Я чувствую, вас ждёт неожиданное открытие.
Построение индекса — это и есть сортировка, чего там смотреть-то? В общем случае построение индекса выливается во внешнюю сортировку, а ее стоимость зависит от соотношения размеров буферов в ОП и общего объема данных. Осталось учесть, что стоимость записи многократно больше стоимости чтения... А если временные таблицы расположены на том же диске, что и данные, и головка диска дергается то на чтение исходных данных, то на запись промежуточных, то там вообще труба выходит... И эту "трубу", что характерно, ты не увидишь в SQL Profiler, бо он не покажет проседание производительности от дергания головки жесткого диска. И там такое может выйти, что любыми оценками в терминах логических чтений можно пренебречь как незначащими... Вы хоть раз замеряли эффект от установки SORT_IN_TEMPDB? Я чувствую, тебя ждёт неожиданное открытие.
V>>Нет, это означает, что были взяты нужные типы данных для нужных платформ. Это в C# интерфейсы коллекций завязали на платформенно-независимый int, что есть большая грабля сама по себе, а в С++ используется платформенно-зависимый тип size_t. И вообще, беззнаковая арифметика в почете, бо позволяет делать на одно сравнение меньше для выяснения соответствия требуемому диапазону. S> Ок, не будем копать в эту сторону.
Ну и зря... бо в C# действительно приходится бодаться с переполнениями, странно что народ так редко возмущается. Отсутствие банального typedef размножает какую-нить простейшую проблему многократно по коду, вместо того, чтобы дать возможность справиться с ней раз и навсегда в одном месте.
V>>Оно даже не компилируется, если ты про приведение к Int64... писал поздно и быстро. Ожидал сие возражение там же сразу, оно было очевидным после отправки без предварительного просмотра... S>Даже если бы компилировалось — там сам подход неверен.
Приведение к Int64 было обязательно для выяснения знака операции через вычитание. Мы просто решали не ту проблему и не с того конца. Проблема-то в том, что генерики не поддерживают статические ф-ии, поэтому нужен интерфейс компаратора, но результат работы компаратора, в свою очередь, надо зафиксировать в некоем типе, не зависящем от типа аргумента. Почему там int, а не enum {less/before, equal, greater/after}? Вот тебе любезно подложенная грабля by design, которая своим происхождением вовсе не обязана тому, что ты пытался на ее примере показать.
Здравствуйте, vdimas, Вы писали:
V>"Что" и "как" — это вполне интуитивные понятия, имеющие однозначную языковую семантику, а вовсе не наивные.
Наивно представление о том, что "как" обязательно предоставляет больше информации, чем "что".
V>Т.е. таки разногласия в понимании взаимоотношений понятий "как" и "что"?
Разногласия в понимании того, чем отличаются декларативное представление программ от императивного.
V>Ты утверждал, что иммутабельное означает декларативное.
Нет. Я утверждал, что отсутствие побочных эффектов означает декларативное. Причём, естественно, не случайное отсутствие побочных эффектов, а такое, которое с гарантией.
V>printf("%d", x); — точно так же декларативен для некоей низлежащей системы, как и сигма.
Ничего подобного. printf() работает с консолью и меняет её состояние. Поэтому порядок вызова printf-ов важен, и printf — императивен на 100%.
V>Эти спекуляции ведут в никуда, ведь ты сначала отвергаешь взаимоотношение РИ и РА как уровней с разными степенями подробностей,
Да нет там никаких разных степеней подробностей. РА и РИ взаимно однозначно отображаются друг на друга — см. теорему Кодда.
S>>А можно пояснить подробнее, что значит "использовать наоборот"?
V>Чем фильтрация сигнала от обнаружения отличается? Тем, что фильтрация в общем случае налагает лишь некоторые ограничения, которыми должен обладать сигнал, но реальная конструкция сигнала может быть гораздо сложнее, чем возможно выделить одним фильтром или даже несколькими фильтрами, т.к. кодирование информации может случается разное, она может быть закодирована как статические или даже динамические х-ки, получаемые сразу по многим фильтрам. Поэтому каждый фильтр "просто делает своё дело", не подозревая, как будут использоваться результаты его труда. Например, все структурные формулы РИ приводимы к одному квантору EXISTS, который использует сигму как детектор по своему определению, но после перевода конкретного квантора EXISTS в формулу РА, состоящую из продукций, проекций и ограничений, ты не можешь по каждой отдельной выделенной операции судить, какой же был вид исходного (целевого) квантора. Т.е. в каждом отдельном операторе РА непонятно, как же было сформулировано "что" в исходном операторе РИ.
Ок, это понятно. Непонятно только, при чём тут декларативность vs императивность. Вместо них противопоставляется декомпозированное описание и монолитное.
V>Эта К будет при каждой операции чтения, т.е. при N, независимо от затрат на обход индекса. Эти логарифмические затраты просто не видны обычно на фоне чтения страниц "вразнобой".
Эти логарифмические затраты обычно и определяют количество чтений страниц.
V>Еще раз, эта сложность у операции декартова произведения по-определению.
Join — это не декартово произведение. V>Я знаю, что ты настаиваешь на оценке исключительно логического чтения. Но, логические не значат физические и не только на чтение с диска нужны ресурсы.
Я вас разочарую — CPU-затраты на join ведут себя с той же асимптотикой, что и на логические чтения. Вот только K при этих O там совсем другой.
V>Фи, как низкопробно. Т.е. ты считаешь, что основная лишняя нагрузка на СУБД — это работа по обслуживанию запросов, передачи по сети каждый раз заново заголовков таблиц вместе с данными и т.д.?
Основная лишняя нагрузка — это парсинг запроса, построение плана, использование метаданных. Для интереса, попробуйте замерить, сколько стоит выполнить select 0 на удалённом MS SQL.
Рассуждения про внутреннее устройство СУБД я поскипаю, т.к. не могу без слёз их читать.
V>И как он порвет, если редко бывает так, что по одной таблице выполняется join только по одному и тому же индексу? Кластерный же один только. Т.е. для одного сценария порвет, а другие сольют.
Ну, то есть другими словами, если в join придётся таки применять некластерный индекс, то всё резко станет плохо. Отлично, вы постепенно начинаете понимать, как всё работает.
V>Ну и ты сам увидел на лишнее чтение на строку. Поэтому если делается join не по кластерному, то имеем лишнее логическое чтение на каждую строку.
Правильно. Это и есть основной недостаток некластерных индексов.
V>ИМХО, случай, когда для некоей таблицы во всех сценариях выборки, происходящих вокруг нее встречается только один вид join, это таки "очень некоторые".
Угу. А теперь попробуйте мне доказать, что для этой таблицы кластерный индекс вовсе не нужен. Вы же такой их противник, нет?
V>Я рассказал о внешних эффектах, которые были обнаружены и обкатаны многократно во всех вариантах. Стоит вернуться и попытаться соотнести свое представление о кишках этой СУБД и причин производимых ими эффектов.
У вас рассказы о внешних эффектах волшебным образом меняются по ходу беседы. Из этого можно сделать банальный вывод, что применяемая вами методика исследования мира не даёт полезных результатов, зато даёт вредные.
S>>Ой, как интересно. А в прошлый раз вы рассказывали ровно наоборот — вы заменяли кластерные индексы на некластерные, и сокращали размер ключа с 4х байт до 2х. S>>Видите, как заметно меняется прошлое, стоит разобраться в вопросе, да?
V>Я упоминал каждый из способов, который давал прибавки к эффективности, многократно. Нигде ничего не меняется. Да, заменял кластерные индексы по уникальному ключу на некластерные, а кластерные оставлял для неуникальных (внешних, например, или индексов для поиска).
Ну вот это уже больше похоже на правду. И прекрасно согласуется с теми критериями, которые я приводил 40 постов назад, а вы смеялись.
V>Ну и во всех гайдлайнах настоятельно MS советует отделять оперативные данные от исторических первой строчкой рекомендаций. Причем, и даже разносить их по разным серверам. Дык, а в твоей системе координат, коль речь идет о разных таблицах, какая фиг разница, не правда ли? Ведь количество логических чтений независимо для независимых запросов...
Вы уже один раз посмеялись над моими знаниями в СУБД. Предлагаю не продолжать — опять ведь в лужу сядете.
V>Какая разница, как конкретно устроена оценочная ф-ия?
Как бы устройство оценочной функции принципиально — именно оно определяет способность СУБД выбрать оптимальный план.
V>Чем дальше, тем больше будет методик составления сей оценочной ф-ии и способов представления статистики для нее. Мы уже давно договорились, что ее вид f(x1, x2, x3, ...), т.е. обычный черный ящик.
Я не знаю, с кем и о чём вы договорились. Вижу только, что никакой литературы об устройстве оптимизаторов запросов вы не читали, и для вас эта область помечена "тут живут драконы".
V>Я утверждал, что породить всевозможные комбинации последовательностей операций для последующей оценки весовой ф-ией можно как раз с помощью аппарата РА.
Используется расширенный аппарат РА — в нём отношения аннотированы дополнительной информацией. В частности, есть информация о том, какие отношения эквивалентны, и насколько они эквивалентны. Что и позволяет оптимизатору запрос по таблице превращать в запрос по индексу.
V>Вот это ты и отрицаешь до сих пор, и я хочу таки услышать, какой для этого исопльзуется аппарат. Мне плевать на конкретную оценочню ф-ю, расскажи, как строиться и модифицируется план запросов, который потом оценивается. V>Я фиг его знает почему ты решил, что для этих вещей исопльзуется какая-то особая, недоступная простым смертным, технология... Хотя в деле организации индексов мало что поменялось с выхода первых СУБД.
Почему недоступная-то? Всё доступно. Я ссылку на учебник дал. То, чего там нет, легко найти в публикациях. Просто применяемый аппарат шире, чем классическая РА.
V>Это смотря какой join и как организованы данные.
V>Какой нах FILESTREAM, когда речь идет о страницах с обычными данными?
Ну вот "страницы с обычными данными" никогда вам не дадут скорость чтения, близкую к ФС. Попробуйте сами сравнить скорость отдачи данных со скоростью чтения с диска — это нетрудно.
V>Насчет "приближаются к скорости чистого чтения" — это иди учи матчасть сам... Не приближаются, а в точности равны, бо работают через memory-mapped file.
Ну вы же только что сами мне рассказывали про то, что логические чтения — не единственные затраты? V>Дело, конечно, в неумении автоматически детектить моменты, когда требуется конкурентность, от моментов, когда не особо требуется. Это я намекаю, что уровней изоляции во встроенных движках обычно поменьше, а сценарий простой полной блокировки очень дешевы в условиях малого кол-ва одновременных запросов, но когда сами запросы относительно тяжелы. Но MS SQL, похоже, всегда создает копии страниц в ОП (хотя сами страницы, скорее всего читает так же через memory-mapped file), и работает уже с ними...
Нет, не создаёт. Зачем вы продолжаете оперировать домыслами, когда можно просто пойти в документацию и почитать?
Кстати, вы же вроде бы исходники смотрели? Я понимаю, что это враньё, но вы уж врите согласованно. Неужто вы бы не заметили копирования страниц, если смотрели даже на выравнивание данных внутри страницы?
V>ИМХО, если стоимость запроса была известна заранее, то вполне мог бы быть некий "порог" конкурентности для конкретной таблицы или целого файла данных, чтобы работать с данными по месту.
Ну, расскажите мне, для чего MS SQL будет копировать страницы.
V>Построение индекса — это и есть сортировка, чего там смотреть-то?
Вы зря не выполняете домашние задания. Так вы ничему не научитесь.
V>В общем случае построение индекса выливается во внешнюю сортировку, а ее стоимость зависит от соотношения размеров буферов в ОП и общего объема данных.
Пренебрежём тем, что у нас есть ОП. Стоимость построения индекса — это O(N log N). V>Осталось учесть, что стоимость записи многократно больше стоимости чтения...
И всё равно это будет O(N log N), только коэффициент будет учитывать и записи, и чтения. V>А если временные таблицы расположены на том же диске, что и данные, и головка диска дергается то на чтение исходных данных, то на запись промежуточных, то там вообще труба выходит...
Да не будет никакой трубы. Будет O(N log N) c плохим коэффициентом. Ничего военного. Наличие большой ОП и разнесение на разные диски способны всего лишь улучшить коэффициенты, но не могут повлиять на асимптотику.
V>Ну и зря... бо в C# действительно приходится бодаться с переполнениями, странно что народ так редко возмущается. Отсутствие банального typedef размножает какую-нить простейшую проблему многократно по коду, вместо того, чтобы дать возможность справиться с ней раз и навсегда в одном месте.
Как раз в C# проблема с переполнениями детектируется элементарно. В отличие от менее удачных языков.
V>Приведение к Int64 было обязательно для выяснения знака операции через вычитание.
Но обратное приведение к int тут же теряет знак обратно.
V>Мы просто решали не ту проблему и не с того конца. Проблема-то в том, что генерики не поддерживают статические ф-ии, поэтому нужен интерфейс компаратора, но результат работы компаратора, в свою очередь, надо зафиксировать в некоем типе, не зависящем от типа аргумента. Почему там int, а не enum {less/before, equal, greater/after}? Вот тебе любезно подложенная грабля by design, которая своим происхождением вовсе не обязана тому, что ты пытался на ее примере показать.
Правильные соображения. Конечно лучше не иметь таких ловушек вовсе. Однако попадание в ловушку — именно следствие непонимания того, что школьная арифметика не работает в компьютере.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>2. присвоение переменной эквивалентно присвоение полю DG>>3. получение значения переменной эквивалентно получению значения поля S>И это чушь. Я это не использовал. Что бы делать утверждения относительно кода с сахаром, нужно знать, во что он разворачивается. Я произвел соответствующее преобразование. Все. Никаких спекуляций об эквивалентности и идентичности.
шаманизм в его ярком проявлении.
вместо того, чтобы рассуждать "челы из микрософт делают преобразование на основе таких-то и таких-то правил эквивалентности и поэтому оно есть правильное" ты рассуждаешь "так как это преобразование делают челы из микрософт значит оно есть правильное".
второй подход плох тем, что в твоей карте мира не остается возможности делать утверждения: преобразования компилятора правильные или нет и при каких условиях
в том-то и дело, что в данном случае замена переменной на объект делается на основе имеющейся эквивалентности переменной и поля объекта, и ничего нового придумано не было.
в c#-е переменная и поле того же типа полностью эквиваленты (за исключением времени жизни). и переменную можно считать частным случаем поля.
вот эквивалентность поля и простого свойства в .net-е страдает намного сильнее (мало того, что они не полиморфны с точки зрения реализации (хотя полиморфны с точки зрения поведения)), так есть еще такие операции как ref и out, которые поддерживают поля, но не поддерживают свойства. хотя эквивалентность поведения и здесь сохраняется, ref может быть заменен на два сообщения(две операции) get/set в виде двух делегатов или интерфейса с двумя методами, а out заменен на одно сообщение set (в виде интерфейса с одним методом или делегатом)
S>Само ООП в вашем расширении совершенно не нуждается, и прекрасно работает без него. С возможностью расширять модель ООП никто не спорил с самого начала. Вы пытались доказать, что можно получить ООП, ослабив требования к одной из составляющих модели. Увы.
в большинстве случаев, расширение происходит через ослабление ряда исходных требований.
например, ОТО расширяет классическую механику, ослабляя базовые требования классической механики
1.время абсолютно, то есть промежутки времени между любыми двумя событиями одинаковы во всех произвольно движущихся системах отсчёта;
2.пространство абсолютно, то есть расстояние между двумя любыми материальными точками одинаково во всех произвольно движущихся системах отсчёта.
при этом классическая механика становится вырожденным случаем ОТО.
тоже самое, например, при переходе от действительных чисел к комплексным: ослабляется требование, что из отрицательных чисел нельзя брать корень, и происходит расширение: действительные числа становятся вырожденным случаем комплексных.
ООП, как минимум, расширяется по трем направлениям:
1. понятие объект не обязано соответствовать физическому воплощению в виде объекта из ООП языка программирования
2. инкапсуляция рассматривается для относительного наблюдателя, а не абсолютного
3. время квантованное. и квант времени рассмотрения может не один к одному соответствовать атомарному кванту времени изменения состояния программы
Здравствуйте, Sinclair, Вы писали:
V>>"Что" и "как" — это вполне интуитивные понятия, имеющие однозначную языковую семантику, а вовсе не наивные. S>Наивно представление о том, что "как" обязательно предоставляет больше информации, чем "что".
Тем не менее, считается что сами уровни, подходящие под "как" и "что" находятся в односторонней зависимости, например, одному и тому же "что" может соответствовать много вариантов "как", каждый со своими лишними подробностями, не требуемыми на уровне "что". Мои рассуждения исходили из того, что на любом из вариантов уровня "как" видны примитивы уровня "что" (являются целью, "точкой входа" и т.д.), т.е. уровень "как" владеет одновременно своими подробностями и подробностями вышестоящей системы, в то время с уровня "что" подробности уровня "как" являются лишними.
V>>Т.е. таки разногласия в понимании взаимоотношений понятий "как" и "что"? S>Разногласия в понимании того, чем отличаются декларативное представление программ от императивного.
V>>Ты утверждал, что иммутабельное означает декларативное. S>Нет. Я утверждал, что отсутствие побочных эффектов означает декларативное. Причём, естественно, не случайное отсутствие побочных эффектов, а такое, которое с гарантией.
Гарантия — это атрибут модели, придуманный тобой. И правильно придуманый, бо я бы возразил, что без проблем на декларативном ЯП писать без побочных эффектов. А гарантии в том же С++ можно обеспечить через const, например. Получим декларативный подход?
V>>printf("%d", x); — точно так же декларативен для некоей низлежащей системы, как и сигма. S>Ничего подобного. printf() работает с консолью и меняет её состояние. Поэтому порядок вызова printf-ов важен, и printf — императивен на 100%.
Нет никакого порядка вызова printf() внутри реализации этой ф-ии, есть только одна эта задача на своем уровне, которая понятия не имеет о вызовах других printf(). И есть некий низлежащий слой ОС. И эта задача вполне может быть выполнена без побочных эффектов на своем уровне, передавая данные "куда-то дальше"... В чистых функциональных языках тоже ведь как-то ввод-вывод делают, просто разграничивают, что это делает "кто-то другой" через библиотеки.
V>>Эти спекуляции ведут в никуда, ведь ты сначала отвергаешь взаимоотношение РИ и РА как уровней с разными степенями подробностей, S>Да нет там никаких разных степеней подробностей. РА и РИ взаимно однозначно отображаются друг на друга — см. теорему Кодда.
Дык, сам смотри внимательней. И смотри на реальные примеры тоже. В общем случае один оператор РИ требует много операторов РА, обратное неверно. Т.е. насчет взаимно-однозначного отображения... реверс-инжениринг работает по такому-же принципу, но из этого никто не делает далекоидущие выводы о равенстве декларативности условия и его решения. Бо из решения не всегда очевидно условие. А теорема Кодда доказывает нечто иное, что на РА можно выразить любые операторы РИ, т.е. РА обладает достаточной полнотой, чтобы являться инструментом реализации РИ. (справедливости ради в теореме доказывается не достаточность полноты РА для РИ, а эквивалентность, т.е. в РА были включены те и только те операции, которые требуются для выражения операторов РИ и никакие больше... это и было сутью теоремы)
Ладно, точка зрения понятна, любопытно было только упоминание некоей теоремы Черча, интересно, какую из них ты там имел ввиду как аргумент? В остальном, с подобной т.з. сталкивался не раз и пока не видел более-менее интересных аргументов.
S>Ок, это понятно. Непонятно только, при чём тут декларативность vs императивность.
При том, что изменяющееся состояние приписали "императивному" исторически. Императивность — это последовательность инструкций, факт обязательности побочных эффектов не является неоспоримым. Даже при взгляде на дерево вычислений математического выражения, в каждом узле этого дерева хранятся именно инструкции/операторы, которые вычисляются по направлению к корню. Ну и... даже в императивном программировании 99% математических вычислений абсолютно чисты. Отсюда и до бесконечности можно опять начинать спекулировать про те самые гарантии... но такой спор априори неинтересен.
V>>Эта К будет при каждой операции чтения, т.е. при N, независимо от затрат на обход индекса. Эти логарифмические затраты просто не видны обычно на фоне чтения страниц "вразнобой". S>Эти логарифмические затраты обычно и определяют количество чтений страниц.
Это чтение одной строки в случае индекса имеет логарифмическую вид сложности некий K1 * O(log N), а чтение N страниц "вразнобой", а не подряд, имеет сложность O(N) cо своим совершенно другим К2, бо степень упорядоченность страниц данных обычно отличается от степени упорядоченности страниц индекса. Итого, логарифмический вид будет при малом K1, но прямо пропорционально при большем (обычно) K2.
V>>Еще раз, эта сложность у операции декартова произведения по-определению. S>Join — это не декартово произведение.
О, решил повториться?
inner/outer/right/left/cross/full... не?
V>>Я знаю, что ты настаиваешь на оценке исключительно логического чтения. Но, логические не значат физические и не только на чтение с диска нужны ресурсы. S>Я вас разочарую — CPU-затраты на join ведут себя с той же асимптотикой, что и на логические чтения. Вот только K при этих O там совсем другой.
Это бред сивой кобылы. Одну асимптотику можно выражать через другую, только если твой "другой" K постоянен, а если он зависит от того, сколько необходимых данных будут на каждой странице, то выражать одну сложность через другую бесполезно. В итоговую сложность надо будет включать отношения размеров доступного кеша и данных.
V>>Фи, как низкопробно. Т.е. ты считаешь, что основная лишняя нагрузка на СУБД — это работа по обслуживанию запросов, передачи по сети каждый раз заново заголовков таблиц вместе с данными и т.д.? S>Основная лишняя нагрузка — это парсинг запроса, построение плана, использование метаданных. Для интереса, попробуйте замерить, сколько стоит выполнить select 0 на удалённом MS SQL.
Речь шла об отличиях. И там и там есть как парсинг запроса, так и построение плана и использование метаданных. Для интереса попробуй замерить сам, только не через TCP и не на удаленном, а на локальном... бо измерять плохосконфигурированный TCP я, пожалуй, не стану, select 0 не будет ответом, почему сервер тормозит даже тогда, когда все дополнительные действия составляют мизер от общих затрат.
V>>ИМХО, случай, когда для некоей таблицы во всех сценариях выборки, происходящих вокруг нее встречается только один вид join, это таки "очень некоторые". S>Угу. А теперь попробуйте мне доказать, что для этой таблицы кластерный индекс вовсе не нужен. Вы же такой их противник, нет?
Откуда "противник"? Я описал свои наблюдения относительно использования их в кач-ве уникальных ключей, где они хорошо работают, а где не очень. И как выяснилось в твоих же экспериментах, для "широких" таблиц кластерный индекс начинает работать как некластерный на чтении. Так зачем его тартить на это? Далее говорилось, что для небольших по-объему данных и "узкого" ключа основной ключ имеет смысл делать таки кластерным, невзирая ни на что. Т.е. я получал прирост эффективности для таких данных, невзирая на всевозможные join по совсем другим индексам. Возможно, хорошо начинают сказываться всякие политики упреждающего чтения, которые меньше промахиваются на малых объемах данных или еще что-нить, о чем можно только гадать. Т.е. возможны всякие эффекты, которые хрен увидишь в логических чтениях, но хорошо увидишь по возросшей отзывчивости основных операций после того как база немного "разогреется". Факт "разогрева" тоже простой асимптотикой логических чтений хрен опишешь...
V>>Я рассказал о внешних эффектах, которые были обнаружены и обкатаны многократно во всех вариантах. Стоит вернуться и попытаться соотнести свое представление о кишках этой СУБД и причин производимых ими эффектов. S>У вас рассказы о внешних эффектах волшебным образом меняются по ходу беседы. Из этого можно сделать банальный вывод, что применяемая вами методика исследования мира не даёт полезных результатов, зато даёт вредные.
Гы, исследовать эффективность программных продуктов можно только на тестах в конкретном аппаратном окружении для конкретного характера данных... Остальное — грубая профанация.
S>Ну вот это уже больше похоже на правду. И прекрасно согласуется с теми критериями, которые я приводил 40 постов назад, а вы смеялись.
Те критерии совершенно не объясняют устойчиво наблюдаемых эффектов. А в Санта-Клауса я не верю.
V>>Ну и во всех гайдлайнах настоятельно MS советует отделять оперативные данные от исторических первой строчкой рекомендаций. Причем, и даже разносить их по разным серверам. Дык, а в твоей системе координат, коль речь идет о разных таблицах, какая фиг разница, не правда ли? Ведь количество логических чтений независимо для независимых запросов... S>Вы уже один раз посмеялись над моими знаниями в СУБД. Предлагаю не продолжать — опять ведь в лужу сядете.
Таки это действительно MS настойчиво пишет в гайдах, и я не понял этот финт в кач-ве комментария. Ты точно на этот абзац отвечал, не промахнулся случаем?
Характерно, что мы пришли к тому же довольно быстро, еще до того, как был выпущен блестящий BOL к 7-ке и множество наработанных практик/советов от самой же MS. И неприятно поразило то, что для предыдущего варианта файлового движка СУБД мы могли позволить себе куда как больший оперативный период на той же технике.
V>>Какая разница, как конкретно устроена оценочная ф-ия? S>Как бы устройство оценочной функции принципиально — именно оно определяет способность СУБД выбрать оптимальный план.
Для алгоритма перебора вариантов это не играет рояли.
V>>Чем дальше, тем больше будет методик составления сей оценочной ф-ии и способов представления статистики для нее. Мы уже давно договорились, что ее вид f(x1, x2, x3, ...), т.е. обычный черный ящик. S>Я не знаю, с кем и о чём вы договорились. Вижу только, что никакой литературы об устройстве оптимизаторов запросов вы не читали, и для вас эта область помечена "тут живут драконы".
Разве? Наоборот видно, что я всяко лучше понимаю, как именно рождаются варианты планов запросов. Относительно оптимизаций мне достаточно знать, для чего нужна статистика и как именно она исопльзуется с весовой ф-ией. Устройство весовой ф-ии не интересует, разумеется, бо сам писал такие же многократно, и это дело зависит от совсем уж конкретики конкретной СУБД. Сколько разных СУБД увидишь, столько будет разных оценочных ф-ий, это непереносимые/неуниверсальные знания.
V>>Я утверждал, что породить всевозможные комбинации последовательностей операций для последующей оценки весовой ф-ией можно как раз с помощью аппарата РА. S>Используется расширенный аппарат РА — в нём отношения аннотированы дополнительной информацией. В частности, есть информация о том, какие отношения эквивалентны, и насколько они эквивалентны.
Давай конкретней, где ты это берешь? Эта информация (зависимости) есть на уровне реляционной модели by design, ничего расширять не надо. Конкретная декомпозиция — то и есть набор отношений. При известной исходной схеме и зависимостях любые отношения даже проверять на эквивалентность не надо, достаточно посмотреть на мн-во атрибутов, входящих в отношение. И речь не об одноименности атрибутов, которую легко получить в SQL, а именно о мн-ве уникальных атрибутов конкретной схемы в рамках реляционной модели. Разумеется, индексы по некоей таблице априори оперируют уникальными атрибутами, т.е. колонками этой таблицы. Расширения, конечно, есть, но оно малость в другом — в использовании вычислимых полей. Но и это слабо тянет на расширения, бо вычислимые поля порождаются простой операцией проекции и переименования. Я потому и подбивал тебя на конкретику относительно твоих планов запросов, чтобы уже обсудить наконец хоть что-то по делу и попунктно. Жаль, что ты продолжаешь вилять.
Конечно, я в спешке написал малость некорректно относительно именно РА, бо РА не умеет составлять собственные формулы. Это очевидно. (кроме преобразования уже готовых, ссылку на примеры преобразований ты давал). Речь именно о применимости реляционной модели в деле составления плана запросов, то бишь перебора и оценки вариантов. Ведь тут придется вернуться к самому началу и вспомнить, как именно происходит оценка плана запроса и заново взглянуть на твои попытки выставить "bookmark lookup" как некую совершенно особую операцию.
Надеюсь, ты уже давно понял, что я говорил с самого начала относительно этой темы. А знание тобой конкретных оценочных подходов похвально, конечно, но не интерсует, уже говорил. Из-за постоянной изменчивости этой темы.
S>Что и позволяет оптимизатору запрос по таблице превращать в запрос по индексу.
Так что же это "что"?
S>Почему недоступная-то? Всё доступно. Я ссылку на учебник дал. То, чего там нет, легко найти в публикациях. Просто применяемый аппарат шире, чем классическая РА.
Вообще, мы зацепились за реляционную модель вначале, фокус на РА у нас был больше по другой теме, с которой начинается этот пост...
Давай попробуем наконец разобрать попунктно, где и что шире. Бо нагенерили кучу взаимных рефлексий, где-то должна начинаться польза.
Язык SQL представляет собой смесь операторов реляционной алгебры и выражений реляционного исчисления, использующий синтаксис, близкий к фразам английского языка и расширенный дополнительными возможностями, отсутствующими в реляционной алгебре и реляционном исчислении.
Я вижу нереляционные расширения языка SQL (если отбросить хинты, операции конфигурирования или DDL) в основном в виде императивных конструкций вокруг курсоров. Неуникальность строк таблиц мы уже обсуждали, только не до конца. Так и не было показано, что твои же преобразования из РА, будучи примененным к таким неуникальным данным, вдруг станут неверными.
Один из самых мощных и наиболее часто используемый оператор SELECT реализует все операции реляционной алгебры.
Не могу не согласиться. И только по нему составляется обcуждаемый нами план запроса. Собс-но, реляционная алгебра именно выборкой и занимается. Поэтому мне и странно рассуждать о других возможностях SQL, коль речь идет о выборке. Мало ли, что есть в некоем языке программирования... они сейчас сплошь мультипарадигменные.
V>>Насчет "приближаются к скорости чистого чтения" — это иди учи матчасть сам... Не приближаются, а в точности равны, бо работают через memory-mapped file. S>Ну вы же только что сами мне рассказывали про то, что логические чтения — не единственные затраты? V>>Дело, конечно, в неумении автоматически детектить моменты, когда требуется конкурентность, от моментов, когда не особо требуется. Это я намекаю, что уровней изоляции во встроенных движках обычно поменьше, а сценарий простой полной блокировки очень дешевы в условиях малого кол-ва одновременных запросов, но когда сами запросы относительно тяжелы. Но MS SQL, похоже, всегда создает копии страниц в ОП (хотя сами страницы, скорее всего читает так же через memory-mapped file), и работает уже с ними... S>Нет, не создаёт. Зачем вы продолжаете оперировать домыслами, когда можно просто пойти в документацию и почитать? S>Кстати, вы же вроде бы исходники смотрели? Я понимаю, что это враньё, но вы уж врите согласованно.
Разбирать их целиком было невозможно принципиально, так что использовались в основном для непонятных моментов и эффектов, примерно как Reflector для дотнета. Исходники 6-ки таки были для гос-конторы.
S>Неужто вы бы не заметили копирования страниц, если смотрели даже на выравнивание данных внутри страницы?
The buffer manager manages the functions for reading data or index pages from the database disk files into the buffer cache and writing modified pages back to disk.
Запись целиком страницы обратно говорит о том, что, во первых это хреново, записывать 8k, если поменялся всего один байт (неважно, lazy там или еще что), а во вторых, что сама страница не отображена как участок memory-mapped file, т.е. таки используется копия страницы в памяти. Хотя при BULK заливке или для твоих каких-то новых FILESTREAM (никогда не работал с ними) таки используется маппинг памяти на файлы (это видно по кодам ошибок), но при этом в журнал ничего не пишется и транзакционность не особо обеспечивается.
И да, подсмотренному вопросу выравнивания данных внутри страницы абсолютно фиолетово, с помощью какой именно технологии чтения эта страница была получена.
V>>ИМХО, если стоимость запроса была известна заранее, то вполне мог бы быть некий "порог" конкурентности для конкретной таблицы или целого файла данных, чтобы работать с данными по месту. S>Ну, расскажите мне, для чего MS SQL будет копировать страницы.
Чтение и запись в стиле обычного IO — это и есть копирование, в сравнении с непосредственой работой memory-mapped files. Как, по-твоему, работает кеш страниц в MS SQL?
V>>Построение индекса — это и есть сортировка, чего там смотреть-то? S>Вы зря не выполняете домашние задания. Так вы ничему не научитесь.
Ах, не сортировка? Что-то новое открыли в науке индексов? Или построение упорядоченной коллекции, типа сбалансированного дерева — это не сортировка? Как любопытно-то...
V>>В общем случае построение индекса выливается во внешнюю сортировку, а ее стоимость зависит от соотношения размеров буферов в ОП и общего объема данных. S>Пренебрежём тем, что у нас есть ОП. Стоимость построения индекса — это O(N log N). V>>Осталось учесть, что стоимость записи многократно больше стоимости чтения... S>И всё равно это будет O(N log N), только коэффициент будет учитывать и записи, и чтения.
Только один коэф не сможет учесть-то, так что надо больше составляющих, и при каждой поставить свой коэф.
V>>А если временные таблицы расположены на том же диске, что и данные, и головка диска дергается то на чтение исходных данных, то на запись промежуточных, то там вообще труба выходит... S>Да не будет никакой трубы. Будет O(N log N) c плохим коэффициентом. Ничего военного. Наличие большой ОП и разнесение на разные диски способны всего лишь улучшить коэффициенты, но не могут повлиять на асимптотику.
Могут, ты ведь сам настаиваешь, что асимптотика по логическим чтениям такова для многих операций, что остальными компонентами асимптотики можно пренебречь. Так и здесь. Кол-во операций записи на самом деле будет O(N). Стоимость слияния после сортировки — тоже O(N). В случае дергания головки будет лишь страшное К.
V>>Ну и зря... бо в C# действительно приходится бодаться с переполнениями, странно что народ так редко возмущается. Отсутствие банального typedef размножает какую-нить простейшую проблему многократно по коду, вместо того, чтобы дать возможность справиться с ней раз и навсегда в одном месте. S>Как раз в C# проблема с переполнениями детектируется элементарно. В отличие от менее удачных языков.
Например? В С++ в компиляторах есть опция — проверять признак переполнения или нет.
Но не в этом суть, почему используют вычитание. Суть в том, чтобы попытаться убежать от лишнего if, бо в современных процах при неудачном предсказании ветвление может стоить столько же, сколько десятки целочисленных операций. Я думал это и так понятно для коллег, иначе никто бы не ломал голову над вариантами с вычитанием, а тупо написали бы на if.
V>>Приведение к Int64 было обязательно для выяснения знака операции через вычитание. S>Но обратное приведение к int тут же теряет знак обратно.
Спасибо, просто открыл глаза...
V>>Мы просто решали не ту проблему и не с того конца. Проблема-то в том, что генерики не поддерживают статические ф-ии, поэтому нужен интерфейс компаратора, но результат работы компаратора, в свою очередь, надо зафиксировать в некоем типе, не зависящем от типа аргумента. Почему там int, а не enum {less/before, equal, greater/after}? Вот тебе любезно подложенная грабля by design, которая своим происхождением вовсе не обязана тому, что ты пытался на ее примере показать. S>Правильные соображения. Конечно лучше не иметь таких ловушек вовсе. Однако попадание в ловушку — именно следствие непонимания того, что школьная арифметика не работает в компьютере.
Я уже объяснил, откуда потенциальное попадание в ловушку — из-за специальной попытки избежать if. Дело в том, что хоть С/С++ меняется медленно и очень консервативен, но стандартная библиотека удивительно целостностна в плане возможных косяков и принятых инженерных решений, в отличие от либ дотнета. Например, результат сравнения как int есть только для ф-ии над цепочкой char, т.е. никакая грабля в тот прототип, который был взят потом в дотнет, не была заложена. Грабля появилась после обобщения. А по мне — так экономия на спичках, бо виртуальный вызов метода компаратора "съест" любые сэкономленные спички.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, Sinclair, Вы писали:
V>>>printf("%d", x); — точно так же декларативен для некоей низлежащей системы, как и сигма. S>>Ничего подобного. printf() работает с консолью и меняет её состояние. Поэтому порядок вызова printf-ов важен, и printf — императивен на 100%.
V>Нет никакого порядка вызова printf() внутри реализации этой ф-ии, есть только одна эта задача на своем уровне, которая понятия не имеет о вызовах других printf().
Эта задача есть инструкция control flow. printf не учавствует в вычислении, в описании того что нужно получить. V>И есть некий низлежащий слой ОС. И эта задача вполне может быть выполнена без побочных эффектов на своем уровне, передавая данные "куда-то дальше"...
Передача данных "куда-то дальше" — это и есть императив. И нет никаких уровней побочных эффектов. Побочный эффект либо есть либо нет. V>В чистых функциональных языках тоже ведь как-то ввод-вывод делают, просто разграничивают, что это делает "кто-то другой" через библиотеки.
В случае хаскеля, например, ввод-вывод не делают (не выполняют). Вместо этого результатом функции main является комбинация императивных действий и вычислений. Такая комбинация получается с помощью декларативного описания, именно она является целью декларативных вычислений. Выполнение ввода-вывода остается таким образом за бортом ФЯ.
В сравнении с таким подходом, результатом выполнения main у C-подобных языков является int или void. И printf для вычисления этого значения не нужен.
Здравствуйте, DarkGray, Вы писали: DG>в большинстве случаев, расширение происходит через ослабление ряда исходных требований.
Нет. Вы неправильно понимаете, что такое "требование". DG>при этом классическая механика становится вырожденным случаем ОТО.
Всё как раз наоборот. Появляется требование ограниченности скорости передачи информации, из которого выводится всё остальное. В том числе и изменённые требования к метрическому тензору. Если просто убрать требования, которые вы предлагаете, получится вовсе не ОТО.
DG>тоже самое, например, при переходе от действительных чисел к комплексным: ослабляется требование, что из отрицательных чисел нельзя брать корень, и происходит расширение: действительные числа становятся вырожденным случаем комплексных.
Нет. Всё как раз наоборот: появляется требование замкнутости множества относительно операций возведения в произвольную степень, и из него выводится всё остальное.
Требования "нельзя брать корень из отрицательных чисел" в определении действительных чисел нет.
DG>ООП, как минимум, расширяется по трем направлениям: DG>1. понятие объект не обязано соответствовать физическому воплощению в виде объекта из ООП языка программирования
Это не расширение. Базовое ООП ничего не говорит о физическом воплощении. DG>2. инкапсуляция рассматривается для относительного наблюдателя, а не абсолютного
Инкапсуляция с самого начала не рассматривается для абсолютного наблюдателя. DG>3. время квантованное. и квант времени рассмотрения может не один к одному соответствовать атомарному кванту времени изменения состояния программы
Время в ООП и так квантованное. Мы с вами это уже обсуждали.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>в большинстве случаев, расширение происходит через ослабление ряда исходных требований. S>Нет. Вы неправильно понимаете, что такое "требование".
такая формулировка означает, что ты знаешь что такое "требование", а значит у тебя есть полное определение, что такое "требование" в модели. иначе это у тебя чухня, а не знание.
DG>>при этом классическая механика становится вырожденным случаем ОТО. S>Всё как раз наоборот. Появляется требование ограниченности скорости передачи информации, из которого выводится всё остальное. В том числе и изменённые требования к метрическому тензору. Если просто убрать требования, которые вы предлагаете, получится вовсе не ОТО.
интересная гипотеза, но из ограниченности скорости передачи информации не вытекает, что время становится относительным, а пространство искривленным.
горизонт событий есть даже на такой простой системке, как игра жизнь, и ни о каком относительности времени разговор там еще не идет.
может у того авторитета которого ты считаешь цитируешь были еще какие-то добавления к этому допущению, из которых уже и вытекало искривление пространства и времени?
DG>>тоже самое, например, при переходе от действительных чисел к комплексным: ослабляется требование, что из отрицательных чисел нельзя брать корень, и происходит расширение: действительные числа становятся вырожденным случаем комплексных. S>Нет. Всё как раз наоборот: появляется требование замкнутости множества относительно операций возведения в произвольную степень, и из него выводится всё остальное.
это новая цель(необходимость), а не требование (в математическом смысле).
если тебе не нравится предыдущее требование, то можно рассмотреть ослабление другого требования: число есть результат измерения реального непрерывного пространства (именно поэтому эти числа называются вещественными или действительными)
S>Требования "нельзя брать корень из отрицательных чисел" в определении действительных чисел нет.
DG>>ООП, как минимум, расширяется по трем направлениям: DG>>1. понятие объект не обязано соответствовать физическому воплощению в виде объекта из ООП языка программирования S>Это не расширение. Базовое ООП ничего не говорит о физическом воплощении.
значит ты согласен, что переменная, свойство, группа объектов могут рассматриваться как отдельный объект?
DG>>2. инкапсуляция рассматривается для относительного наблюдателя, а не абсолютного S>Инкапсуляция с самого начала не рассматривается для абсолютного наблюдателя.
переформулируй это конструктивно (без "не"): с точки зрения чего инкапсуляция рассматривается?
DG>>3. время квантованное. и квант времени рассмотрения может не один к одному соответствовать атомарному кванту времени изменения состояния программы S>Время в ООП и так квантованное. Мы с вами это уже обсуждали.
а что со второй частью — можно ли в качестве кванта рассмотрения брать произвольный промежуток времени?
Здравствуйте, vdimas, Вы писали:
V>Тем не менее, считается что сами уровни, подходящие под "как" и "что" находятся в односторонней зависимости, например, одному и тому же "что" может соответствовать много вариантов "как", каждый со своими лишними подробностями, не требуемыми на уровне "что". Мои рассуждения исходили из того, что на любом из вариантов уровня "как" видны примитивы уровня "что" (являются целью, "точкой входа" и т.д.), т.е. уровень "как" владеет одновременно своими подробностями и подробностями вышестоящей системы, в то время с уровня "что" подробности уровня "как" являются лишними.
Это интересное мнение. Откуда тогда так популярны соревнования типа "что делает эта программа", если на любом из вариантов уровня "как" видны примитивы уровня "что"?
V>Гарантия — это атрибут модели, придуманный тобой. И правильно придуманый, бо я бы возразил, что без проблем на декларативном ЯП писать без побочных эффектов. А гарантии в том же С++ можно обеспечить через const, например. Получим декларативный подход?
Ну, мы же знаем, что гарантиям const в C++ — грош цена. Но если вы обеспечите такие гарантии — то, конечно же, мы получим декларативный подход.
V>>>printf("%d", x); — точно так же декларативен для некоей низлежащей системы, как и сигма. S>>Ничего подобного. printf() работает с консолью и меняет её состояние. Поэтому порядок вызова printf-ов важен, и printf — императивен на 100%.
V>Нет никакого порядка вызова printf() внутри реализации этой ф-ии,
При чём тут реализация? Вы что, всеръёз полагаете, что результат
printf("hello, ");
printf("world");
и результат
printf("hello, ");
printf("world");
— одинаковы? V>есть только одна эта задача на своем уровне, которая понятия не имеет о вызовах других printf(). И есть некий низлежащий слой ОС. И эта задача вполне может быть выполнена без побочных эффектов на своем уровне, передавая данные "куда-то дальше"...
Нет, она не может быть выполнена без побочных эффектов. Она целиком и полностью опирается на определённое поведение разделяемого состояния. V>В чистых функциональных языках тоже ведь как-то ввод-вывод делают, просто разграничивают, что это делает "кто-то другой" через библиотеки.
А вы поинтересуйтесь, как же так в чистых функциональных языках делают ввод-вывод. Там ведь нет ничего сложного — просто вместо неявного состояния вычислителя, на котором работают императивные программы, вводится явное состояние аргумента. Грубо говоря, вместо void printf(...) у нас появляется
Console printf(this Console in, String text);
Сама printf здесь не имеет побочных эффектов — её можно вызывать на одном и том же аргументе сколько угодно раз, и результат всегда будет одинаковым.
Чтобы задать порядок, надо явно писать
console.printf("Hello").printf("World")
V>При том, что изменяющееся состояние приписали "императивному" исторически. Императивность — это последовательность инструкций, факт обязательности побочных эффектов не является неоспоримым.
Вы, я вижу, не понимаете простой вещи. Если нет побочных эффектов, то "последовательность" инструкций — фикция. Единственный способ принудить инструкции исполняться последовательно — ввести зависимость их друг от друга. В императивном программировании зависимость вводится через побочные эффекты. В декларативном программировании все зависимости — явные, поэтому можно делать всякие интересные трансформации с порядком выполнения (и с выполнением вообще). В частности, можно вычислить первые N чисел Фибоначчи не за N^2, а за N, несмотря на явно рекурсивное определение этой функции.
V>Даже при взгляде на дерево вычислений математического выражения, в каждом узле этого дерева хранятся именно инструкции/операторы, которые вычисляются по направлению к корню.
Ну да, есть отношения частичного порядка, заданные зависимостями. Но для дерева с N листьями у нас есть минимум 2^N вариантов последовательности выполнения, если нет побочных эффектов. Если побочные эффекты есть, то у нас есть ровно 1 вариант последовательности, который даст заданный результат.
V>Это чтение одной строки в случае индекса имеет логарифмическую вид сложности некий K1 * O(log N), а чтение N страниц "вразнобой", а не подряд, имеет сложность O(N) cо своим совершенно другим К2, бо степень упорядоченность страниц данных обычно отличается от степени упорядоченности страниц индекса. Итого, логарифмический вид будет при малом K1, но прямо пропорционально при большем (обычно) K2.
Вы путаете разные N. Стоимость поиска одной строки — O(log N), где N — количество строк в отношении, в котором мы ищем.
Стоимость поиска M строк, соответственно, равна O(M*log(N)).
V>Это бред сивой кобылы. Одну асимптотику можно выражать через другую, только если твой "другой" K постоянен, а если он зависит от того, сколько необходимых данных будут на каждой странице, то выражать одну сложность через другую бесполезно. В итоговую сложность надо будет включать отношения размеров доступного кеша и данных.
Прекратите пороть чушь. Вся прелесть логических чтений — в том, что они дают пессимистичную оценку. То есть наличие кэша всего лишь означает, что часть логических чтений удастся выполнить без физического обращения к диску. Вы сами предложили рассматривать случай, когда данные многократно превышают размер ОП — в этом случае сache hit ratio можно пренебречь, и считать, что он нулевой.
В этом случае у нас все коэффициенты станут фиксированными, их зависимостью от N и M можно будет пренебречь. И, конечно же, O(K1*M*logN+K2*M*logN) всё ещё сведётся к O(M*logN). Вы где вообще учились, что вам такие вещи приходится разжёвывать?
V>Откуда "противник"? Я описал свои наблюдения относительно использования их в кач-ве уникальных ключей, где они хорошо работают, а где не очень. И как выяснилось в твоих же экспериментах, для "широких" таблиц кластерный индекс начинает работать как некластерный на чтении. Так зачем его тартить на это? Далее говорилось, что для небольших по-объему данных и "узкого" ключа основной ключ имеет смысл делать таки кластерным, невзирая ни на что. Т.е. я получал прирост эффективности для таких данных, невзирая на всевозможные join по совсем другим индексам. Возможно, хорошо начинают сказываться всякие политики упреждающего чтения, которые меньше промахиваются на малых объемах данных или еще что-нить, о чем можно только гадать. Т.е. возможны всякие эффекты, которые хрен увидишь в логических чтениях, но хорошо увидишь по возросшей отзывчивости основных операций после того как база немного "разогреется". Факт "разогрева" тоже простой асимптотикой логических чтений хрен опишешь...
Ваши наблюдения как были некорректными, так и остались. Вернитесь в начало и перечитайте критерии уместности применения кластерных индексов, которые я вам написал. Если у вас после этих сорока постов всё ещё остались вопросы про то, как работают кластерные индексы, и как они используются в джойнах — пишите, не стесняйтесь.
V>Гы, исследовать эффективность программных продуктов можно только на тестах в конкретном аппаратном окружении для конкретного характера данных... Остальное — грубая профанация. S>>Ну вот это уже больше похоже на правду. И прекрасно согласуется с теми критериями, которые я приводил 40 постов назад, а вы смеялись. V>Те критерии совершенно не объясняют устойчиво наблюдаемых эффектов. А в Санта-Клауса я не верю.
Ооо, начинается. Какие именно эффекты, необъяснимые приведёнными критериями, вы смогли получить? Не стесняйтесь — приведите код эксперимента.
V>Таки это действительно MS настойчиво пишет в гайдах, и я не понял этот финт в кач-ве комментария. Ты точно на этот абзац отвечал, не промахнулся случаем?
Я отвечал на тот, где пачка смайликов, и вы пытаетесь смеяться над моим подходом. Объясню подробнее: вы уже две недели упорно демонстрируете непонимание простейших фактов из архитектуры MS SQL. В процессе объяснения этих элементарных фактов вы успели неоднократно сделать совершенно необоснованные предположения относительно моей квалификации, нарываясь на п.5. правил, и много смеялись. Теперь элементарные факты мы выяснили, несмотря на ваше активное сопротивление.
Вы продолжаете наезжать на моё понимание и опыт в СУБД, теперь переходя к эффектам следующего порядка. Вы что, после всего этого разговора, ещё надеетесь где-то в этой области меня подколоть? Ну-ну.
V>Для алгоритма перебора вариантов это не играет рояли.
О да. Интересное заблуждение.
V>Разве? Наоборот видно, что я всяко лучше понимаю, как именно рождаются варианты планов запросов.
V>Давай конкретней, где ты это берешь?
Я дал вам ссылки на учебники по устройству СУБД. Читайте. V>Эта информация (зависимости) есть на уровне реляционной модели by design, ничего расширять не надо.
Покажите мне, где эта информация есть на уровне реляционной модели. В реляционной модели понятие "отношения" достаточно чётко определено, и что там есть, и чего нету, написано очень подробно.
S>>Почему недоступная-то? Всё доступно. Я ссылку на учебник дал. То, чего там нет, легко найти в публикациях. Просто применяемый аппарат шире, чем классическая РА.
V>Разбирать их целиком было невозможно принципиально, так что использовались в основном для непонятных моментов и эффектов, примерно как Reflector для дотнета. Исходники 6-ки таки были для гос-конторы.
В прошлый раз это было "вплоть до 2000".
V>Похоже, ты не понял, что есть копирование страниц в сравнении с работой через memory-mapping. V>http://msdn.microsoft.com/en-us/library/aa337560.aspx V>http://msdn.microsoft.com/en-us/library/aa337525.aspx
V>Например: V>
V>The buffer manager manages the functions for reading data or index pages from the database disk files into the buffer cache and writing modified pages back to disk.
V>Запись целиком страницы обратно говорит о том, что, во первых это хреново, записывать 8k, если поменялся всего один байт (неважно, lazy там или еще что),
А вот конкретно это говорит о том, что вы не имеете представления о том, как работает чтение/запись в современных устройствах хранения (включая HDD и SSD).
Потому что записать меньше страницы на диск вообще нельзя. В теории СУБД традиционно принято оценивать характеристики в логических чтениях, а в практике — в IOPS. Современной аппаратуре всё равно, записать 1 байт или 1 екстент в 64кб.
V>а во вторых, что сама страница не отображена как участок memory-mapped file, т.е. таки используется копия страницы в памяти. Хотя при BULK заливке или для твоих каких-то новых FILESTREAM (никогда не работал с ними) таки используется маппинг памяти на файлы (это видно по кодам ошибок), но при этом в журнал ничего не пишется и транзакционность не особо обеспечивается.
Вы сваливаете в одну кучу механику взаимодействия с файлом данных и с файлом журнала, а также понятие транзакционности. Там у вас тоже монолит, да?
V>>>ИМХО, если стоимость запроса была известна заранее, то вполне мог бы быть некий "порог" конкурентности для конкретной таблицы или целого файла данных, чтобы работать с данными по месту. S>>Ну, расскажите мне, для чего MS SQL будет копировать страницы.
V>Чтение и запись в стиле обычного IO — это и есть копирование, в сравнении с непосредственой работой memory-mapped files. Как, по-твоему, работает кеш страниц в MS SQL?
V>Ах, не сортировка? Что-то новое открыли в науке индексов? Или построение упорядоченной коллекции, типа сбалансированного дерева — это не сортировка? Как любопытно-то...
Сортировка. Но вы же поленились посмотреть стоимость этой сортировки.
S>>И всё равно это будет O(N log N), только коэффициент будет учитывать и записи, и чтения.
V>Только один коэф не сможет учесть-то, так что надо больше составляющих, и при каждой поставить свой коэф.
Вот у нас формула вида K1*N*logN + K2*N*logN. Вы правда думаете, что это не равно (K1+K2)*N*logN? Или у вас какое-то другое мнение о составляющих этой формулы?
V>>>А если временные таблицы расположены на том же диске, что и данные, и головка диска дергается то на чтение исходных данных, то на запись промежуточных, то там вообще труба выходит... S>>Да не будет никакой трубы. Будет O(N log N) c плохим коэффициентом. Ничего военного. Наличие большой ОП и разнесение на разные диски способны всего лишь улучшить коэффициенты, но не могут повлиять на асимптотику.
V>Могут, ты ведь сам настаиваешь, что асимптотика по логическим чтениям такова для многих операций, что остальными компонентами асимптотики можно пренебречь.
Так и здесь. Кол-во операций записи на самом деле будет O(N). Стоимость слияния после сортировки — тоже O(N). В случае дергания головки будет лишь страшное К.
Ок, если вам хочется отбросить младшие члены ряда — пусть будет O(N). Несортированная сторона Join даст ещё M. Итого, имеем линейную асимптотику — O(N+M).
А вы, помнится, пугали меня O(N*M). Почувствуйте разницу.
S>>Как раз в C# проблема с переполнениями детектируется элементарно. В отличие от менее удачных языков. V>Например? В С++ в компиляторах есть опция — проверять признак переполнения или нет.
Это в каких конкретно компиляторах? Или вы имеете в виду опции "отключить warning при возможном переполнении"?
В С# рекомендую курить ключевое слово checked.
V>Спасибо, просто открыл глаза...
Пожалуйста. Вы обращайтесь, если что.
V>Я уже объяснил, откуда потенциальное попадание в ловушку — из-за специальной попытки избежать if.
Да неважно, откуда появилось потенциальное попадание.
Это же был просто пример кода, который на первый взгляд кажется корректным. Не нужно высасывать из пальца историю, стоящую за этим кодом.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>интересная гипотеза, но из ограниченности скорости передачи информации не вытекает, что время становится относительным, а пространство искривленным.
Откройте учебник физики, и посмотрите, как именно выводятся преобразования Лоренца.
С искривлением пространства немножко посложнее, туда я вас лезть просить не буду.
DG>это новая цель(необходимость), а не требование (в математическом смысле). DG>если тебе не нравится предыдущее требование, то можно рассмотреть ослабление другого требования: число есть результат измерения реального непрерывного пространства (именно поэтому эти числа называются вещественными или действительными)
Нет такого требования в математике. Почитайте РТФМ, насчёт требований к действительным числам.
DG>>>ООП, как минимум, расширяется по трем направлениям: DG>>>1. понятие объект не обязано соответствовать физическому воплощению в виде объекта из ООП языка программирования S>>Это не расширение. Базовое ООП ничего не говорит о физическом воплощении. DG>значит ты согласен, что переменная, свойство, группа объектов могут рассматриваться как отдельный объект?
Всё, что удовлетворяет определениям — может рассматриваться как объект. Мы же говорим про математические основы ООП, а не про конкретную реализацию.
DG>переформулируй это конструктивно (без "не"): с точки зрения чего инкапсуляция рассматривается?
А там нет конструктивной формулировки. Инкапсуляция всего лишь постулирует невозможность "подсмотреть" состояние объекта иначе, как через его поведение.
DG>>переформулируй это конструктивно (без "не"): с точки зрения чего инкапсуляция рассматривается? S>А там нет конструктивной формулировки. Инкапсуляция всего лишь постулирует невозможность "подсмотреть" состояние объекта иначе, как через его поведение.
согласен ли ты с более сильной формулировкой?:
выводы об объекте должны делаться только на основе его интерфейса (и не должны рассматриваться учитываться детали реализации)
Здравствуйте, DarkGray, Вы писали: DG>согласен ли ты с более сильной формулировкой?: DG>выводы об объекте должны делаться только на основе его интерфейса (и не должны рассматриваться учитываться детали реализации)
Нет.
1. Не определено понятие "интерфейс"
2. Не определено понятие "выводы"
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>согласен ли ты с более сильной формулировкой?: DG>>выводы об объекте должны делаться только на основе его интерфейса (и не должны рассматриваться учитываться детали реализации) S>Нет. S>1. Не определено понятие "интерфейс"
набор сообщений допустимый для использования в данном месте использования объекта
S>2. Не определено понятие "выводы"
ок. пусть будет для начала один вывод: является или не является поведение двух объектов одинаковым
S> ООП не подразумевает никакого "абсолютного наблюдателя".
согласен. но абсолютный наблюдатель может появиться (а может и не появиться), когда делаются те или иные утверждения о конкретной системе.
возьмем следующий код:
void main()
{
var x = new X();
x.Message();
var y = new Y();
y.Message();
}
class X
{
public void Message(){}
}
class Y
{
Y1 y1 = new Y1();
public void Message(){y1.Message();}
}
class Y1
{
public void Message(){}
}
с точки зрения функции main(относительного наблюдателя) поведение объектов X и Y полностью одинаковое: посылается сообщение Message и ничего не происходит. и если для функции main разрешен лишь публичный интерфейс объектов X и Y, то у нее вообще нет способа узнать, что они отличаются
и лишь с позиции абсолютного наблюдателя мы знаем, что поведение объекта X отличается от поведение объекта Y (объект Y дополнительно посылает сообщение объекту Y1)
S> Всё, что удовлетворяет определениям — может рассматриваться как объект. Мы же говорим про математические основы ООП, а не про конкретную реализацию.
значит ты согласен с тем, что любую программу (множество объектов Os) можно представить как два объекта: объект Oi (где Oi из множества Os) и объект Oiw (весь остальной мир: все объекты из множества Os, кроме объекта Oi)?
Здравствуйте, DarkGray, Вы писали:
DG>>>согласен ли ты с более сильной формулировкой?: DG>>>выводы об объекте должны делаться только на основе его интерфейса (и не должны рассматриваться учитываться детали реализации) S>>Нет. S>>1. Не определено понятие "интерфейс" DG>набор сообщений допустимый для использования в данном месте использования объекта
Экий вы шустрый. Вы сейчас пытаетесь ввести понятие классификации. Оно а) лишнее и б) его введение — дорогая штука (в объёме матаппарата, который нужно корректно построить). Десятком слов тут не обойдёшься. В частности, нужно определить понятие "допустимого сообщения" и понятие "место использования объекта".
S>>2. Не определено понятие "выводы" DG>ок. пусть будет для начала один вывод: является или не является поведение двух объектов одинаковым
Ну, в таком случае я вижу некоторую тавтологию. В том смысле, что вы предлагаете судить о поведении объектов по их поведению, т.к. интерфейс в вашем определении сведётся (хоть и не сразу) к поведению объекта.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали: DG>согласен. но абсолютный наблюдатель может появиться (а может и не появиться), когда делаются те или иные утверждения о конкретной системе.
Абсолютного наблюдателя можно ввести искусственно в некоторую модель, и построить на основе этой модели конкретную систему. Но это совершенно необязательно.
DG>с точки зрения функции main(относительного наблюдателя) поведение объектов X и Y полностью одинаковое: посылается сообщение Message и ничего не происходит. и если для функции main разрешен лишь публичный интерфейс объектов X и Y, то у нее вообще нет способа узнать, что они отличаются DG>и лишь с позиции абсолютного наблюдателя мы знаем, что поведение объекта X отличается от поведение объекта Y (объект Y дополнительно посылает сообщение объекту Y1)
Безо всякого абсолютного наблюдателя мы знаем, что поведение объекта X отличается от поведения объекта Y — достаточно посмотреть на него с точки зрения объекта Y1, который тоже относительный наблюдатель. И вот слово "невозможно" в определении инкапсуляции означает "независимо от того, с позиции какого наблюдателя мы ведём наблюдение".
S>> Всё, что удовлетворяет определениям — может рассматриваться как объект. Мы же говорим про математические основы ООП, а не про конкретную реализацию. DG>значит ты согласен с тем, что любую программу (множество объектов Os) можно представить как два объекта: объект Oi (где Oi из множества Os) и объект Oiw (весь остальной мир: все объекты из множества Os, кроме объекта Oi)?
Тут есть некоторая сложность: если объект Оi "осведомлён" о наличии объектов Ok, Ol, Om, On, то склеить их все в один, не нарушив целостность модели, нельзя.
Благодаря идентичности, объект Oi прекрасно отличает ссылки на разные объекты от ссылок на один и тот же объект.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>с точки зрения функции main(относительного наблюдателя) поведение объектов X и Y полностью одинаковое: посылается сообщение Message и ничего не происходит. и если для функции main разрешен лишь публичный интерфейс объектов X и Y, то у нее вообще нет способа узнать, что они отличаются DG>>и лишь с позиции абсолютного наблюдателя мы знаем, что поведение объекта X отличается от поведение объекта Y (объект Y дополнительно посылает сообщение объекту Y1)
S>Безо всякого абсолютного наблюдателя мы знаем, что поведение объекта X отличается от поведения объекта Y — достаточно посмотреть на него с точки зрения объекта Y1, который тоже относительный наблюдатель.
во-первых: это будет точка зрения наблюдателя Y1, которая имеет слабое отношение к наблюдателю main
во-вторых: Y1 — может быть деталью реализации объекта Y и тогда ты не имеешь его брать в качестве одного из наблюдателей за поведением объекта Y
можно даже это явно зафиксировать сделав Y1 приватным
class Y
{
Y1 y1 = new Y1();
public void Message(){y1.Message();}
class Y1
{
public void Message(){}
}
}
S> И вот слово "невозможно" в определении инкапсуляции означает "независимо от того, с позиции какого наблюдателя мы ведём наблюдение".
ок. возьмем следующий код (модифицировав объект X и обозначив как Xr)
void main()
{
var x = new Xr();
x.Message();
var y = new Y();
y.Message();
}
class Xr
{
Y1 y1 = new Y1();
public void Message()
{
if (new Random().Next() < 0.8)
y1.Message();
}
}
class Y
{
Y1 y1 = new Y1();
public void Message(){y1.Message();}
}
class Y1
{
public void Message(){}
}
в данном случае, и с позиции наблюдателя main и с позиции наблюдателя Y1 поведение одно и тоже:
для main Xr и Y ничего не делают,
а для Y1 объекты Xr и Y иногда присылают сообщение.
и только с позиции абсолютного наблюдателя (либо из деталей реализации) мы понимаем, что поведение Xr и поведение Y различно.
S> поведение объекта X отличается от поведения объекта Y — достаточно посмотреть на него с точки зрения объекта Y1, который тоже относительный наблюдатель
здесь как минимум используется неявное требование, что утверждение main об объектах X и Y (один это объект, или два разных) должно быть тем же самым, что и мнение Y1.
или другими словами есть два подхода:
утверждения об объектах X и Y должны быть непротиворечивыми с точки зрения каждого наблюдателя
утверждения об объектах X и Y должны быть непротиворечивыми с точки зрения совокупности всех утверждений наблюдателей
или более формально:
в первом случае — непротиворечивость для всех наблюдателей(объектов) вводится как: непротиворечивость утверждений для всех наблюдателей(объектов) := and(непротиворечивость утверждений для каждого наблюдателя(объекта))
во втором случае — непротиворечивость для всех наблюдателей(объектов) вводится как: непротиворечивость утверждений для всех наблюдателей(объектов) := непротиворечивость(объединение утверждений для каждого объекта(наблюдателя))
первый подход для краткости называют относительным (непротиворечивость сохраняется лишь относительно одно наблюдателя), второй подход — абсолютным (непротиворечивость сохраняется для абсолютного наблюдателя)
S>>> Всё, что удовлетворяет определениям — может рассматриваться как объект. Мы же говорим про математические основы ООП, а не про конкретную реализацию. DG>>значит ты согласен с тем, что любую программу (множество объектов Os) можно представить как два объекта: объект Oi (где Oi из множества Os) и объект Oiw (весь остальной мир: все объекты из множества Os, кроме объекта Oi)? S>Тут есть некоторая сложность: если объект Оi "осведомлён" о наличии объектов Ok, Ol, Om, On, то склеить их все в один, не нарушив целостность модели, нельзя. S>Благодаря идентичности, объект Oi прекрасно отличает ссылки на разные объекты от ссылок на один и тот же объект.
исходную программу (множество объектов Os) назовем построение 0
построение с множеством объектов Oi и объектом Oiw — назовем построение 1.
в построении 1:
объекты Oj (j != i) считаются ссылками на один большой объект Oiw (и соответственно, идентичность объектов в построении 0 переходит в идентичность ссылок в построении 1)
сообщения от Oi к Oj в построении 1 считаются как сообщения от Oi к Oiw и к аргументам еще добавляется Oj
сообщения от Oj к Oi в построении 1 считаются как сообщения от Oiw к Oi, аргументы те же самые
S>Благодаря идентичности, объект Oi прекрасно отличает ссылки на разные объекты от ссылок на один и тот же объект.
и соответственно в построении 1 объект Oi различает лишь ссылки на объект Oiw, но не более.
S>>>1. Не определено понятие "интерфейс" DG>>набор сообщений допустимый для использования в данном месте использования объекта S>Экий вы шустрый. Вы сейчас пытаетесь ввести понятие классификации. Оно а) лишнее и б) его введение — дорогая штука (в объёме матаппарата, который нужно корректно построить). Десятком слов тут не обойдёшься. В частности, нужно определить понятие "допустимого сообщения" и понятие "место использования объекта".
классификация еще не требуется (либо стоит уточнить о классификации чего и по каким призникам идет речь).
возьмем декларацию вида
void F(IEnumerable x){...}
это есть конкретное место использования объектов, передаваемых в функцию F,(обозначим такие объекты как x) и при этом фиксируется (если не сказано что либо еще), что функция F имеет право использовать лишь сообщения, которые входят в интерфейс IEnumerable, а не все сообщения которые поддерживает объект x
S>>>2. Не определено понятие "выводы" DG>>ок. пусть будет для начала один вывод: является или не является поведение двух объектов одинаковым S>Ну, в таком случае я вижу некоторую тавтологию. В том смысле, что вы предлагаете судить о поведении объектов по их поведению, т.к. интерфейс в вашем определении сведётся (хоть и не сразу) к поведению объекта.
он сведется к наблюдаемому поведению.
и соответственно я предлагаю отличать поведение объекта вообще от наблюдаемого поведения объекта.
и зафиксировать, что для наблюдателя важно лишь наблюдаемое поведение объекта, а не всякое.
Здравствуйте, DarkGray, Вы писали:
DG>во-первых: это будет точка зрения наблюдателя Y1, которая имеет слабое отношение к наблюдателю main
Помните об относительности — все наблюдатели равноправны.
DG>во-вторых: Y1 — может быть деталью реализации объекта Y и тогда ты не имеешь его брать в качестве одного из наблюдателей за поведением объекта Y
Если это — деталь реализации, то да. Но в примере Y1 всё же является внешним объектом, благодаря чему и появляется возможность различить
DG>можно даже это явно зафиксировать сделав Y1 приватным
Не поможет. Вы прячете ссылку, а не объект.
DG>ок. возьмем следующий код (модифицировав объект X и обозначив как Xr)
DG>в данном случае, и с позиции наблюдателя main и с позиции наблюдателя Y1 поведение одно и тоже: DG>для main Xr и Y ничего не делают, DG>а для Y1 объекты Xr и Y иногда присылают сообщение.
А как же new Random()? Ему Xr постоянно посылает сообщение Next()
DG>здесь как минимум используется неявное требование, что утверждение main об объектах X и Y (один это объект, или два разных) должно быть тем же самым, что и мнение Y1. DG>или другими словами есть два подхода: DG>утверждения об объектах X и Y должны быть непротиворечивыми с точки зрения каждого наблюдателя DG>утверждения об объектах X и Y должны быть непротиворечивыми с точки зрения совокупности всех утверждений наблюдателей
Вы забегаете вперёд. В базовой модели ООП нет никакого глобального анализа поведения объектов (кроме, собственно, принципа причинности). Инкапсуляция не требует согласованности картины, наблюдаемой всеми возможными наблюдателями.
DG>или более формально: DG>в первом случае — непротиворечивость для всех наблюдателей(объектов) вводится как: непротиворечивость утверждений для всех наблюдателей(объектов) := and(непротиворечивость утверждений для каждого наблюдателя(объекта)) DG>во втором случае — непротиворечивость для всех наблюдателей(объектов) вводится как: непротиворечивость утверждений для всех наблюдателей(объектов) := непротиворечивость(объединение утверждений для каждого объекта(наблюдателя)) DG>первый подход для краткости называют относительным (непротиворечивость сохраняется лишь относительно одно наблюдателя), второй подход — абсолютным (непротиворечивость сохраняется для абсолютного наблюдателя)
Ок, пусть так. В базовой модели не требуется наличие абсолютного наблюдателя.
S>>Благодаря идентичности, объект Oi прекрасно отличает ссылки на разные объекты от ссылок на один и тот же объект.
DG>исходную программу (множество объектов Os) назовем построение 0 DG>построение с множеством объектов Oi и объектом Oiw — назовем построение 1.
Непонятно, что такое множество объектов Oi. DG>в построении 1: DG> объекты Oj (j != i) считаются ссылками на один большой объект Oiw (и соответственно, идентичность объектов в построении 0 переходит в идентичность ссылок в построении 1)
То есть объекты Oj всё ещё существуют, но у них нет собственного состояния и поведения — они всего лишь транслируют сообщения некоторому другому объекту Oiw?
Это в принципе изоморфно предыдущему примеру с Xr и Y. C точки зрения объекта Oi ничего не поменяется; с точки зрения объектов Oj разница есть.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали: DG>классификация еще не требуется (либо стоит уточнить о классификации чего и по каким призникам идет речь).
Вы пытаетесь ввести концепцию интерфейса. Когда вы её разовьёте, получите концепцию типа ссылки. Но уже на первом этапе получается, что разные объекты удовлетворяют разным интерфейсам — вот вам и классификация. DG>возьмем декларацию вида DG>
DG>void F(IEnumerable x){...}
DG>
DG>это есть конкретное место использования объектов, передаваемых в функцию F,(обозначим такие объекты как x)
Вы уже ввели понятие функции и понятие интерфейса. Ни того ни другого в базовой модели ООП нет DG> и при этом фиксируется (если не сказано что либо еще), что функция F имеет право использовать лишь сообщения, которые входят в интерфейс IEnumerable, а не все сообщения которые поддерживает объект x
И ввели понятия "сообщения, которые поддерживает объект х" и "сообщения, которые поддерживает интерфейс i"
DG>он сведется к наблюдаемому поведению. DG>и соответственно я предлагаю отличать поведение объекта вообще от наблюдаемого поведения объекта.
А зачем? Зачем нам вообще нужно ненаблюдаемое поведение? Если его невозможно наблюдать, то в него можно только верить. DG>и зафиксировать, что для наблюдателя важно лишь наблюдаемое поведение объекта, а не всякое.
Предлагаю зафиксировать, что ненаблюдаемым поведением можно вообще пренебречь.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>во-вторых: Y1 — может быть деталью реализации объекта Y и тогда ты не имеешь его брать в качестве одного из наблюдателей за поведением объекта Y S>Если это — деталь реализации, то да. Но в примере Y1 всё же является внешним объектом, благодаря чему и появляется возможность различить
могу сказать твоими же словами: определения "внешний объект" в базовой концепции ООП нет.
дай определение — что такое внешний объект. внешний по отношению к чему? и каким образом определяется — объект внешний или нет?
S>А как же new Random()? Ему Xr постоянно посылает сообщение Next()
во-первых: мне необходимо переписать код, создав псевдослучайность без использования внешних объектов, чтобы ты ответил на то, о чем я спрашиваю?
во-вторых: объект Random не умеет отличать кто именно ему послал сообщение (за него это делает внешняя среда). соответственно он как наблюдатель не знает — ему посылает сообщения только какой-то один объект из пары (X,Y), или оба, или вообще кто-то третий.
DG>>здесь как минимум используется неявное требование, что утверждение main об объектах X и Y (один это объект, или два разных) должно быть тем же самым, что и мнение Y1. DG>>или другими словами есть два подхода: DG>>утверждения об объектах X и Y должны быть непротиворечивыми с точки зрения каждого наблюдателя DG>>утверждения об объектах X и Y должны быть непротиворечивыми с точки зрения совокупности всех утверждений наблюдателей S>Вы забегаете вперёд. В базовой модели ООП нет никакого глобального анализа поведения объектов (кроме, собственно, принципа причинности). Инкапсуляция не требует согласованности картины, наблюдаемой всеми возможными наблюдателями.
тогда непонятно на основании чего ты для ответа на вопрос "является ли поведение объектов X и Y для функции main одинаковым?" используешь ответ на вопрос "является ли поведение объектов X и Y для всех объектов одинаковым"?
DG>>или более формально: DG>>в первом случае — непротиворечивость для всех наблюдателей(объектов) вводится как: непротиворечивость утверждений для всех наблюдателей(объектов) := and(непротиворечивость утверждений для каждого наблюдателя(объекта)) DG>>во втором случае — непротиворечивость для всех наблюдателей(объектов) вводится как: непротиворечивость утверждений для всех наблюдателей(объектов) := непротиворечивость(объединение утверждений для каждого объекта(наблюдателя)) DG>>первый подход для краткости называют относительным (непротиворечивость сохраняется лишь относительно одно наблюдателя), второй подход — абсолютным (непротиворечивость сохраняется для абсолютного наблюдателя) S>Ок, пусть так. В базовой модели не требуется наличие абсолютного наблюдателя.
S>Предлагаю зафиксировать, что ненаблюдаемым поведением можно вообще пренебречь.
исходя из этих двух утверждений ответь на вопрос:
поведение(оно же наблюдаемое поведение, т.к. ненаблюдаемым поведением пренебрегаем) объектов X и Y для функции main одинаковое или нет?
S>То есть объекты Oj всё ещё существуют, но у них нет собственного состояния и поведения — они всего лишь транслируют сообщения некоторому другому объекту Oiw?
вот этот вопрос фактически спрашивает "а как оно на самом деле?", или другими словами "а какое оно с точки зрения абсолютного наблюдателя?".
в относительной парадигме может быть лишь утверждение:
объект Oi исходит из модели, что у объектов Oj нет собственного состояния и поведения, и что они всего лишь транслируют сообщения некоторому другому объекту Oiw, и поведение, наблюдаемое объектом Oi, не создает противоречие с этой моделью.
DG>>набор сообщений допустимый для использования в данном месте использования объекта S>Экий вы шустрый. Вы сейчас пытаетесь ввести понятие классификации. Оно а) лишнее и б) его введение — дорогая штука (в объёме матаппарата, который нужно корректно построить). Десятком слов тут не обойдёшься. В частности, нужно определить понятие "допустимого сообщения" и понятие "место использования объекта".
S> Но уже на первом этапе получается, что разные объекты удовлетворяют разным интерфейсам — вот вам и классификация.
ок. пусть будет классификация.
тогда остается вопрос — лишнее для чего?
вся возня с парадигмами программирования (в том числе и с ООП) делается для решения задачи: продвинуться дальше в достижении целей: (максимизация множества решаемых задач, максимальная производительность кода, максимальная скорость разработки, максимальное соответствие работы программы ожидаемому поведению, стоимость разработки, стоимость сопровождения). при этом максимизация происходит как в одной цели за счет других, так есть и общее продвижение.
общее продвижение, в частности, происходит при движении к цели: предсказуемость поведения программы без ее запуска.
и соответственно без классификации объектов невозможно продвинуться к данной цели (предсказуемость поведения программы без ее запуска).
Здравствуйте, DarkGray, Вы писали:
DG>могу сказать твоими же словами: определения "внешний объект" в базовой концепции ООП нет. DG>дай определение — что такое внешний объект. внешний по отношению к чему? и каким образом определяется — объект внешний или нет?
Все объекты внешние. DG>во-первых: мне необходимо переписать код, создав псевдослучайность без использования внешних объектов, чтобы ты ответил на то, о чем я спрашиваю?
Да. DG>во-вторых: объект Random не умеет отличать кто именно ему послал сообщение (за него это делает внешняя среда). соответственно он как наблюдатель не знает — ему
посылает сообщения только какой-то один объект из пары (X,Y), или оба, или вообще кто-то третий.
Да, вы правы — в базовой модели не требуется опознавать отправителя сообщения.
DG>тогда непонятно на основании чего ты для ответа на вопрос "является ли поведение объектов X и Y для функции main одинаковым?" используешь ответ на вопрос "является ли поведение объектов X и Y для всех объектов одинаковым"?
Потому что мне неинтересен вопрос поведения объектов для функции main.
S>>Предлагаю зафиксировать, что ненаблюдаемым поведением можно вообще пренебречь.
DG>исходя из этих двух утверждений ответь на вопрос: DG>поведение(оно же наблюдаемое поведение, т.к. ненаблюдаемым поведением пренебрегаем) объектов X и Y для функции main одинаковое или нет?
В данном примере — да.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>То есть объекты Oj всё ещё существуют, но у них нет собственного состояния и поведения — они всего лишь транслируют сообщения некоторому другому объекту Oiw?
DG>вот этот вопрос фактически спрашивает "а как оно на самом деле?", или другими словами "а какое оно с точки зрения абсолютного наблюдателя?".
Конечно. Мы же с вами являемся "абсолютными наблюдателями" в этой воображаемой модели, поэтому я и проясняю у вас толкование непонятных мне моментов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>ок. пусть будет классификация. DG>тогда остается вопрос — лишнее для чего?
Для базовой модели ООП.
Модель с классами и интерфейсами значительно сложнее, и она опциональна. Скажем, в JavaScript ни классов, ни интерфейсов нет. В SmallTalk нет понятия "допустимое сообщение".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>вот этот вопрос фактически спрашивает "а как оно на самом деле?", или другими словами "а какое оно с точки зрения абсолютного наблюдателя?". S>Конечно. Мы же с вами являемся "абсолютными наблюдателями" в этой воображаемой модели, поэтому я и проясняю у вас толкование непонятных мне моментов.
если последовательно используется относительная парадигма вопрос должен быть другой:
с позиции абсолютного наблюдателя верно ли, что поведение, наблюдаемое объектом Oi, не создает противоречие с его моделью, что у объектов Oj нет собственного состояния и поведения, и что они всего лишь транслируют сообщения некоторому другому объекту Oiw
?
DG>>ок. пусть будет классификация. DG>>тогда остается вопрос — лишнее для чего? S>Для базовой модели ООП. S>Модель с классами и интерфейсами значительно сложнее, и она опциональна. Скажем, в JavaScript ни классов, ни интерфейсов нет. В SmallTalk нет понятия "допустимое сообщение".
один из базовых вариантов классификации поведения:
вырожденным поведением (если не сказано обратное) считается поведение, когда в результате посылки сообщения: ничего не происходит или всегда происходит ошибка (в том числе ошибка компиляции).
допустимые сообщения — это сообщения, которые образуют невырожденное поведение.
S>Модель с классами и интерфейсами значительно сложнее, и она опциональна. Скажем, в JavaScript ни классов, ни интерфейсов нет. В SmallTalk нет понятия "допустимое сообщение".
и класс, и интерфейс — это соглашения, которые могут быть явно поддержаны ЯП, а могут быть зафиксированы неявно в ЯП, или могут быть зафиксированы с помощью внешнего ЯП (например, на ЕЯ в комментариях)
если берем функцию js с кодом вида
function f(x)
{
if (x == null || !x.length)
return;
...
}
и простейшую классификацию: вырожденное/невырожденное поведение, то уже можно сказать, что объект x должен обладать интерфейсом вида (быть не null, и иметь поле length), чтобы функция f имела не вырожденное поведение.
и соответственно можно говорить о том, что в данном коде не явно зафиксировано каким интерфейсом обязан обладать объект x
S> Скажем, в JavaScript ни классов, ни интерфейсов нет.
с первым соглашусь
про второе корректнее сказать, что интерфейс в js есть, но он динамический (имеет возможность меняться по ходу работы программы)
хотя и прототип при определенных условиях можно рассматривать как динамический класс.
S>Да, вы правы — в базовой модели не требуется опознавать отправителя сообщения.
вернемся тогда к исходному коду с X, Y
void main()
{
var x = new X();
x.Message();
var y = new Y();
y.Message();
}
class X
{
public void Message(){}
}
class Y
{
Y1 y1 = new Y1();
public void Message(){y1.Message();}
}
class Y1
{
public void Message(){}
}
в данном случае мы имеем 4 относительных наблюдателя:
main: наблюдает только, что объекты X и Y имеют одинаковое поведение: получают сообщение Message и ничего не делают
X: наблюдает только, что ему кто-то присылает сообщения Message
Y: наблюдает только, что ему кто-то присылает сообщение Message, что он в ответ на это посылает сообщение объекту Y1, который на это ничего не делает
Y1: наблюдает только, что ему кто-то присылает сообщение Message
и имея лишь эти наблюдения невозможно сделать вывод, что поведение объектов X и Y различно.
Здравствуйте, samius, Вы писали:
V>>Нет никакого порядка вызова printf() внутри реализации этой ф-ии, есть только одна эта задача на своем уровне, которая понятия не имеет о вызовах других printf(). S>Эта задача есть инструкция control flow. printf не учавствует в вычислении, в описании того что нужно получить.
Второе предложение можно по-русски?
V>>И есть некий низлежащий слой ОС. И эта задача вполне может быть выполнена без побочных эффектов на своем уровне, передавая данные "куда-то дальше"... S>Передача данных "куда-то дальше" — это и есть императив. И нет никаких уровней побочных эффектов. Побочный эффект либо есть либо нет.
На уровне твоего кода его нет. Я не зря привел ф-ый язык как пример. Т.е. ты никак не можешь достоверно узнать, есть он или нет, бо на твои собственные программные примитивы это никак не влияет. Прямо как в ф-ом языке, где состояние-то есть, но тебе оно недоступно. Да, в случае printf есть требование последовательного исполнения, задаваемого в документации в ф-ии. Для сравнения, IO в Хаскеле задается явно в контракте ф-ии, в отличие от словесной доки по printf. Считай, что императивность сама по себе является элементом декларативности.
V>>В чистых функциональных языках тоже ведь как-то ввод-вывод делают, просто разграничивают, что это делает "кто-то другой" через библиотеки. S>В случае хаскеля, например, ввод-вывод не делают (не выполняют). Вместо этого результатом функции main является комбинация императивных действий и вычислений. Такая комбинация получается с помощью декларативного описания, именно она является целью декларативных вычислений. Выполнение ввода-вывода остается таким образом за бортом ФЯ.
Э нет, за бортом ничего не остается, есть монады, задачи которых — именно образовать цепочку вычислений. Императив. И пусть это делается "чисто функциональными ср-вами" — ничего по-сути не меняется, коль нам гарантируется последовательность вычислений.
S>В сравнении с таким подходом, результатом выполнения main у C-подобных языков является int или void. И printf для вычисления этого значения не нужен.
При чем тут вообще main? В Хаскеле есть ввод-вывод куда угодно, в файл, сокет и т.д., вызываемые из произвольной IO ф-ии. Я пока не увидел, чем IO монада в Хаскеле отличается от тела ф-ии printf. Про State вообще молчу... эмуляция императива как оно есть.
Здравствуйте, Sinclair, Вы писали:
V>>Тем не менее, считается что сами уровни, подходящие под "как" и "что" находятся в односторонней зависимости, например, одному и тому же "что" может соответствовать много вариантов "как", каждый со своими лишними подробностями, не требуемыми на уровне "что". Мои рассуждения исходили из того, что на любом из вариантов уровня "как" видны примитивы уровня "что" (являются целью, "точкой входа" и т.д.), т.е. уровень "как" владеет одновременно своими подробностями и подробностями вышестоящей системы, в то время с уровня "что" подробности уровня "как" являются лишними. S>Это интересное мнение. Откуда тогда так популярны соревнования типа "что делает эта программа", если на любом из вариантов уровня "как" видны примитивы уровня "что"?
Для 99% кода вполне понятно, что оно делает. И даже коментарий — это тоже часть программы, обычно описывающая ту часть контракта, которая невыразима ср-вами используемого ЯП.
V>>Нет никакого порядка вызова printf() внутри реализации этой ф-ии, S>При чём тут реализация? Вы что, всеръёз полагаете, что результат S>
S>printf("hello, ");
S>printf("world");
S>
S>и результат S>
S>printf("hello, ");
S>printf("world");
S>
S>- одинаковы?
Для состояния твоей программы — несомненно одинаковы. Я ведь не зря привел пример ввода-вывода в ф-х языках.
V>>есть только одна эта задача на своем уровне, которая понятия не имеет о вызовах других printf(). И есть некий низлежащий слой ОС. И эта задача вполне может быть выполнена без побочных эффектов на своем уровне, передавая данные "куда-то дальше"... S>Нет, она не может быть выполнена без побочных эффектов. Она целиком и полностью опирается на определённое поведение разделяемого состояния.
Это только у нас в голове так, согласно доке по консоли.
V>>В чистых функциональных языках тоже ведь как-то ввод-вывод делают, просто разграничивают, что это делает "кто-то другой" через библиотеки. S>А вы поинтересуйтесь, как же так в чистых функциональных языках делают ввод-вывод. Там ведь нет ничего сложного — просто вместо неявного состояния вычислителя, на котором работают императивные программы, вводится явное состояние аргумента. Грубо говоря, вместо void printf(...) у нас появляется S>
S>Console printf(this Console in, String text);
S>
S>Сама printf здесь не имеет побочных эффектов — её можно вызывать на одном и том же аргументе сколько угодно раз, и результат всегда будет одинаковым.
Дык, тело сишной printf тоже не имеет никаких побочных эффектов, является полностью реентерабельной. Если бы были побочные эффекты именно внутри кода printf, она не была бы реентерабельной и многопоточной. И да, в printf таки подается FILE (просто в той перегрузке, в которой не подается, используется глобальная переменная). И отличие в Хаскеля лишь в том, что IO-тип Console не надо возвращать обратно как результат ф-ии, бо это лишь частное требование для механики монады IO, которая не нужна в C++.
S>Чтобы задать порядок, надо явно писать S>
S>console.printf("Hello").printf("World")
S>
Вооот... мы дошли до цепочек вычислений в ф-ом программировании, через механизм вложенных вызовов ф-ий, мне даже не пришлось 10-й раз намекать, как для случая РА. Чем не императив? ИМХО, только точкой зрения на происходящее.
V>>При том, что изменяющееся состояние приписали "императивному" исторически. Императивность — это последовательность инструкций, факт обязательности побочных эффектов не является неоспоримым. S>Вы, я вижу, не понимаете простой вещи. Если нет побочных эффектов, то "последовательность" инструкций — фикция.
Это ес-но, речь шла о том, где заканчивается декларативное и начинается императивное. Твои побочные эффекты могут быть нам недоступны, т.е. не влиять на элементы нашей программы, примерно как в монаде IO. В чем тогда отличие якобы декларативного Хаскеля в случае этой монады, и императивной программы, которая использует только "чистые" ф-ии и процедуры, не изменяющие неявно состояния нашей программы?
S>Единственный способ принудить инструкции исполняться последовательно — ввести зависимость их друг от друга. В императивном программировании зависимость вводится через побочные эффекты.
Первое предложение ты написал поторопимшись. У нас уже есть низлежащая аппаратура, которая близка по принципу работы машине Тьюринга, поэтому последовательность инструкций мы имеем как вычислительный базис. Отличие ф-ых языков от императивных в том, что ф-ые скрывают от программиста внутреннюю работу с состоянием, т.е. на уровне пользовательской программы побочных эффектов НЕТ. Я же привел printf не случайно, показав точно такой же случай, что на уровне пользовательской программы нет никаких побочных эффектов. Я понимаю, что тебе сразу захотелось полезть куда-то внутрь, чуть ли не до самой машины Тьюринга и показать мне, что таки состояние есть у консоли "где-то там унутрях"... но это очень толсто, коль этот случай сравнивался с точно таким же аналогичным из ФЯ...
S>В декларативном программировании все зависимости — явные, поэтому можно делать всякие интересные трансформации с порядком выполнения (и с выполнением вообще).
Зависимости вложенных ф-ий конечно явные, задающие порядок вычислений.
S>В частности, можно вычислить первые N чисел Фибоначчи не за N^2, а за N, несмотря на явно рекурсивное определение этой функции.
Это св-во ленивости, а не ф-сти. Точно такой же эффект достижим и в императиве аж бегом, если навертишь свой некий тип Lazy<T>. Не смущает, что сам механизм ленивости основан на запоминании состояния в точке вычисления?
V>>Даже при взгляде на дерево вычислений математического выражения, в каждом узле этого дерева хранятся именно инструкции/операторы, которые вычисляются по направлению к корню. S>Ну да, есть отношения частичного порядка, заданные зависимостями. Но для дерева с N листьями у нас есть минимум 2^N вариантов последовательности выполнения, если нет побочных эффектов. Если побочные эффекты есть, то у нас есть ровно 1 вариант последовательности, который даст заданный результат.
Дык, если ширина каждого слоя узлов ровно 1, то порядок будет ровно 1. Я же не зря этот пример привел, подводя к нужной мысли... но ты и сам его показал на примере цепочки printf.
В общем, я еще с самого начала предупредил, что тема иммутабельности и границ императивности — скользкая. Много холивара и условностей, а львиная доля любой императивной программы — абсолютно чиста с т.з. побочных эффектов над доступными примитивами программы. Сказать, что я заведомо определился с какой-то точкой зрения не могу. В разных спорах участвую с разных сторон. Интересны сугубо аргументы. Бо сдается мне, что прямо на сегодня в этих понятиях слишком много религиозного и зависимости от точки зрения и глубины рассмотрения происходящего. А раз так, то использовать их в кач-ве аргументов следует осторожно или не использовать вообще, предпочитая обсуждать конкретику вместо приема спора, когда вопрос пытаются отнести к некоему "классу" и выстроеному последующему док-ву на принадлежности проблемы к сему классу.
V>>Это чтение одной строки в случае индекса имеет логарифмическую вид сложности некий K1 * O(log N), а чтение N страниц "вразнобой", а не подряд, имеет сложность O(N) cо своим совершенно другим К2, бо степень упорядоченность страниц данных обычно отличается от степени упорядоченности страниц индекса. Итого, логарифмический вид будет при малом K1, но прямо пропорционально при большем (обычно) K2. S>Вы путаете разные N. Стоимость поиска одной строки — O(log N), где N — количество строк в отношении, в котором мы ищем.
Я именно это и сказал, никакой путаницы.
S>Стоимость поиска M строк, соответственно, равна O(M*log(N)).
Ага, вот где путаница, только не у меня. Для случая join мы имеем те же N, а не M (по крайней мере одна из сторон соединения просматривается целиком для любого из join).
Я словесно имел ввиду, что полная формула в пределе такая:
K1 * O(N * log N) + K2 * O(N), где K2 обычно гораздо гораздо хуже K1.
V>>Это бред сивой кобылы. Одну асимптотику можно выражать через другую, только если твой "другой" K постоянен, а если он зависит от того, сколько необходимых данных будут на каждой странице, то выражать одну сложность через другую бесполезно. В итоговую сложность надо будет включать отношения размеров доступного кеша и данных. S>Прекратите пороть чушь. Вся прелесть логических чтений — в том, что они дают пессимистичную оценку.
Очередной бред. При чем тут "пессимистика" и логические чтения? Ты понимаешь смысл символа O() в выражениях асимптотики? Чем отличается от O от Ω? Нет такого понятия "пессимистичная оценка". В терминах O идет ограничение асимптотики сверху. Вовсе не факт, что для реального объема данных, гораздо меньшего, чем в пределе, будет такая "песеммистическая оценка", обычно бывает ровно наоборот, зависимости для малого кол-ва данных обычно гораздо похуже, чем для асимптотики сверху. Ты этого не знаешь, поэтому порешь ерунду насчет "пессимистичности"... Ровно наоборот, оценка сверху зачастую — самая оптимистичная, т.к. для нее отбрасываются незначащие компоненты для бесконечно большого N. И эта оценка именно для логических чтений, независимо ни от какого cache hit ratio для твоих "больших размеров". Характерно, что для малого кол-ва данных тоже может случиться низкий cache hit ratio, например, если каждая страница в некоей выборке будет нужна лишь однажды, и не случится к ней того самого повторного обращения...
S>То есть наличие кэша всего лишь означает, что часть логических чтений удастся выполнить без физического обращения к диску. Вы сами предложили рассматривать случай, когда данные многократно превышают размер ОП — в этом случае сache hit ratio можно пренебречь, и считать, что он нулевой.
Оба предела асимптотики, выраженной в логических чтениях, что нижний, что верхний, никак не зависят от cache hit ratio. Ты сейчас подставляешься по самое нихочу, заканчивай умничать, где не ходил еще ни разу... Есть асимптотика в логических чтениях — я с ней и не спорю. Я лишь заметил, что оценка общей сложности может выглядеть иначе и это действительно так. Тем паче, что не сказал, какая именно асимптотика, а ты уже поскакал куда-то вдаль. ИМХО, дело тут тривиально в том, что реальную сложность трудно оценить абстрактно, а можно только на конкретных соотношениях характеристик ООП и данных, поэтому даются различные виды асимптотики, например, в терминах O для логических чтений. Но т.к. размеры современной ООП таковы, что отличаются от обычных данных уже не на несколько порядков, а дай бог на один, то эти характеристики начинают влиять на реальную сложность и их тоже интересно учитывать. Вот эти мои наблюдения относительно поведения кластерных индексов — они как раз насчет вполне осязаемых соотношений данных были даны, а не "асимптотически сверху", как выдавал рекомендации ты.
S>В этом случае у нас все коэффициенты станут фиксированными, их зависимостью от N и M можно будет пренебречь. И, конечно же, O(K1*M*logN+K2*M*logN) всё ещё сведётся к O(M*logN). Вы где вообще учились, что вам такие вещи приходится разжёвывать?
Позволь спросить, а ты где учился?
Фишка в том, что O(M*logN) не зависит от cache hit ratio даже для физических чтений, бо O — это ограничение асимптотики сверху. Но оценок может быть много, не обязательно оценка сверху. Ты же сам давал ссылку на что-то там по оценке сложности (хоть я и не ходил по ним, бо теорию, в отличии от, знаю неплохо, а оценка сложностей конкретных алгоритмов не интересует пока не столкнусь с ними). Так вот, в твоем оптимизаторе плана запросов фигурирует как раз не верхняя оценка асимптотики сложности, а именно реальная, без всяких O. Для того статистика и нужна, чтобы оперировать (пусть даже с некоторой погрешностью) заведомо известным кол-вом данных.
V>>Откуда "противник"? Я описал свои наблюдения относительно использования их в кач-ве уникальных ключей, где они хорошо работают, а где не очень. И как выяснилось в твоих же экспериментах, для "широких" таблиц кластерный индекс начинает работать как некластерный на чтении. Так зачем его тартить на это? Далее говорилось, что для небольших по-объему данных и "узкого" ключа основной ключ имеет смысл делать таки кластерным, невзирая ни на что. Т.е. я получал прирост эффективности для таких данных, невзирая на всевозможные join по совсем другим индексам. Возможно, хорошо начинают сказываться всякие политики упреждающего чтения, которые меньше промахиваются на малых объемах данных или еще что-нить, о чем можно только гадать. Т.е. возможны всякие эффекты, которые хрен увидишь в логических чтениях, но хорошо увидишь по возросшей отзывчивости основных операций после того как база немного "разогреется". Факт "разогрева" тоже простой асимптотикой логических чтений хрен опишешь...
S>Ваши наблюдения как были некорректными, так и остались.
Наблюдения — это объективная реальность.
V>>Гы, исследовать эффективность программных продуктов можно только на тестах в конкретном аппаратном окружении для конкретного характера данных... Остальное — грубая профанация. S>>>Ну вот это уже больше похоже на правду. И прекрасно согласуется с теми критериями, которые я приводил 40 постов назад, а вы смеялись. V>>Те критерии совершенно не объясняют устойчиво наблюдаемых эффектов. А в Санта-Клауса я не верю. S>Ооо, начинается. Какие именно эффекты, необъяснимые приведёнными критериями, вы смогли получить? Не стесняйтесь — приведите код эксперимента.
Боюсь надо привести базу целиком, слишком много комбинаций. Не стыкуется наблюдение насчет эффективности кластерного основного ключа по относительно небольшим данным (см что я писал). Согласно твоим рекомендациям, это не должно зависеть от размеров данных вообще.
V>>Таки это действительно MS настойчиво пишет в гайдах, и я не понял этот финт в кач-ве комментария. Ты точно на этот абзац отвечал, не промахнулся случаем? S>Я отвечал на тот, где пачка смайликов, и вы пытаетесь смеяться над моим подходом. Объясню подробнее: вы уже две недели упорно демонстрируете непонимание простейших фактов из архитектуры MS SQL. В процессе объяснения этих элементарных фактов вы успели неоднократно сделать совершенно необоснованные предположения относительно моей квалификации, нарываясь на п.5. правил, и много смеялись. Теперь элементарные факты мы выяснили, несмотря на ваше активное сопротивление.
Да ладно тебе, своими "идите почитайте" ты нарываешься везде и всюду, где бы я не встречал твои посты. Заслужено получаешь в ответ. А здесь опять попытался сумничать не по теме обсуждения.
S>Вы продолжаете наезжать на моё понимание и опыт в СУБД, теперь переходя к эффектам следующего порядка. S>Вы что, после всего этого разговора, ещё надеетесь где-то в этой области меня подколоть? Ну-ну.
Я вижу крайне узкоспециализированный опыт и весьма оригинальные эффекты из-за этого, см начало обсуждение. Например о ненужности реляционной модели, и о прочих вредительских советах. Так всегда бывает, когда сложную и объемную область изучают на примере конкретного продукта, непонимая, где и откуда растут ноги, и почему именно так.
V>>Для алгоритма перебора вариантов это не играет рояли. S>О да. Интересное заблуждение.
Осталось продемонстрировать, что ты (а) таки понял утверждение, (б) оно не верно. ИМХО, если выполнишь (а), то (б) отпадет само собой.
V>>Давай конкретней, где ты это берешь? S>Я дал вам ссылки на учебники по устройству СУБД. Читайте.
Дать тебе ссылку на устройство связанного списка?
Еще раз, как именно происходит преобразование структурных формул SQL к вариантам планов запросов, которые ЗАТЕМ оцениваются оценочной ф-ей. И таки частично ты прав, но скорее случайно, чем преднамеренно. Действительно, при переборе планов запросов некоторые ветки перебора могут отсекаться довольно рано, но это было бы известно тебе и так, если бы ты понимал, как именно эти планы строятся по выражениям SQL. И да, в твоей ссылке такой информации нет. Это надо топать в реляционные исчисления. Т.е. в школу, за азбукой. А потом уже садиться за "руководство программисту" к конкретному продукту и прочие твои ссылки "по разметке страниц в моей любимой СУБД".
V>>Эта информация (зависимости) есть на уровне реляционной модели by design, ничего расширять не надо. S>Покажите мне, где эта информация есть на уровне реляционной модели. В реляционной модели понятие "отношения" достаточно чётко определено, и что там есть, и чего нету, написано очень подробно.
Это зависимости. См. что есть реляционная модель. Например, нормализация отношений выполняется только лишь под управлением зависимостей и ничем больше. А ты упоминаешь зависимости как некое расширение. Меня уже порядком утомило твое упрямство, если честно, что ты продолжаешь считать индексы чем-то таким, что стоит совершенно сбоку. Это всего лишь атрибуты физической модели, непонятно, почему к ним неприменимы наработки РА. Это все делал товарищ Кодд, разрабатывал реализацию таблиц, индексов, операций по ним и т.д., так же разрабатывал теоретический аппарат ко всей этой кухне... прихоти ради, если тебя послушать...
S>>>Почему недоступная-то? Всё доступно. Я ссылку на учебник дал. То, чего там нет, легко найти в публикациях. Просто применяемый аппарат шире, чем классическая РА.
Скука.
V>>Разбирать их целиком было невозможно принципиально, так что использовались в основном для непонятных моментов и эффектов, примерно как Reflector для дотнета. Исходники 6-ки таки были для гос-конторы. S>В прошлый раз это было "вплоть до 2000".
В прошлый раз ты читал невнимательно. Вплоть до 2000 серьезно использовался MS SQL, начиная с шестерки. Потом крайне несерьезно, бо перешли на ORM, да и объемы данных для проектов были невелики, да и техника серьезно подросла, т.е. исследовательские работы по самой СУБД были не нужны. Т.е. опыта практически полной писанины приложения на СУБД и тщательного вылизывания эффективности больше не было (фигли для ORM вылизывать).
V>>The buffer manager manages the functions for reading data or index pages from the database disk files into the buffer cache and writing modified pages back to disk.
V>>Запись целиком страницы обратно говорит о том, что, во первых это хреново, записывать 8k, если поменялся всего один байт (неважно, lazy там или еще что), S>А вот конкретно это говорит о том, что вы не имеете представления о том, как работает чтение/запись в современных устройствах хранения (включая HDD и SSD).
Давай прежде посмотрим, как работает memory mapped file, а потом будем делать выводы.
S>Потому что записать меньше страницы на диск вообще нельзя. В теории СУБД традиционно принято оценивать характеристики в логических чтениях, а в практике — в IOPS. Современной аппаратуре всё равно, записать 1 байт или 1 екстент в 64кб.
Не все-равно в затратах копирования данных во внутренний кеш операционки. К тому же, в случае memory mapped file мы даем операционной системе решать, как ей лучше сбрасывать данные, а лучше драйвера ввода-вывода все-равно никто не знает.
В принципе, там суть не в IOPS, разумеется, а в том, что сервер, в отличие от ОС, знает, когда у него конец транзакции, поэтому использует копии страниц кеша, а не пользует память кеша страниц ОС напрямую, как в случае memory mapped file. Твои экстенты — они сугубо для уменьшения кол-ва дорогостоящих операций ввода/вывода, чтобы копировать за раз больше страниц... Но не на диск, разумеется, бо это не серверу решать (вот почему Oracle давно уже разраобтал свою файловую систему, чтобы держать всё под конторлем), а для того лишь, чтобы уменьшить кол-во системных вызовов, каждый из которых относительно дорогой (даже холостой вызов этого последовательного АПИ ввода-вывода стоит единицы микросекунд). И кстати, IOPS на SSD-массивах скоро будет уже под миллионы и выше, при том, что пропускная способность DMA ограничена, так что тебе стоит пересмотреть свои представления. http://www.ixbt.com/news/hard/index.shtml?15/38/75
Основная фишка memory-mapped file в том, что в этом случае мы имеем меньше слоев IO, чем при последовательном способе, т.е. банально меньше копируется данных м/у дисковым кешем операционной системы и нашими буферами (страницами). Я уверен, что в MS SQL будет пересмотрен способ работы со страницами в ближайших версиях, бо сейчас их способ уже малость архаика.
V>>а во вторых, что сама страница не отображена как участок memory-mapped file, т.е. таки используется копия страницы в памяти. Хотя при BULK заливке или для твоих каких-то новых FILESTREAM (никогда не работал с ними) таки используется маппинг памяти на файлы (это видно по кодам ошибок), но при этом в журнал ничего не пишется и транзакционность не особо обеспечивается. S>Вы сваливаете в одну кучу механику взаимодействия с файлом данных и с файлом журнала, а также понятие транзакционности. Там у вас тоже монолит, да?
Я думаю, это ты не способен адекватно воспринимать информацию. Тут я лишь подстраховался на случай возможных спекуляций, что таки MS SQL где-то использует упомянутую технологию. А что спекулировать навязчиво по какой-нить теме ты способен бесконечно — я это уже видел, в вопросе последовательности операций в РА.
V>>Ах, не сортировка? Что-то новое открыли в науке индексов? Или построение упорядоченной коллекции, типа сбалансированного дерева — это не сортировка? Как любопытно-то... S>Сортировка. Но вы же поленились посмотреть стоимость этой сортировки.
Я знаю стоимость внешней сортировки уже более 20 лет как. Да, поленился в 1000-й посмотреть, потому что в верхнем пределе, том самом, которое при O, оно не может быть меньше.
S>>>И всё равно это будет O(N log N), только коэффициент будет учитывать и записи, и чтения.
V>>Только один коэф не сможет учесть-то, так что надо больше составляющих, и при каждой поставить свой коэф. S>Вот у нас формула вида K1*N*logN + K2*N*logN. Вы правда думаете, что это не равно (K1+K2)*N*logN? Или у вас какое-то другое мнение о составляющих этой формулы?
Да, другое. Во втором компоненте будет просто K2*N.
"Идите учите" (С) внешнюю сортировку...
Объединять составляющие в одну формулу я бы не стал. Во-первых, для асимптотики в терминах O все-равно стоит оставить самый быстрорастущий компонент... вот из-за этого и не стал бы... учитывая, что операция записи зачастую на порядок дороже операции чтения, объединять в одну оценку можно только в сферическом вакууме. Т.е. для реальных оценок при таких катастрофически разных К асимптотика O слишком грубая.
V>>>>А если временные таблицы расположены на том же диске, что и данные, и головка диска дергается то на чтение исходных данных, то на запись промежуточных, то там вообще труба выходит... S>>>Да не будет никакой трубы. Будет O(N log N) c плохим коэффициентом. Ничего военного. Наличие большой ОП и разнесение на разные диски способны всего лишь улучшить коэффициенты, но не могут повлиять на асимптотику.
S>Ок, если вам хочется отбросить младшие члены ряда — пусть будет O(N). Несортированная сторона Join даст ещё M. Итого, имеем линейную асимптотику — O(N+M). S>А вы, помнится, пугали меня O(N*M). Почувствуйте разницу.
Пффф, по кругу... Тебе осталось показать, что запись результата мощности O(N*M) будет дешевле сортировки одной из компонент.
S>>>Как раз в C# проблема с переполнениями детектируется элементарно. В отличие от менее удачных языков. V>>Например? В С++ в компиляторах есть опция — проверять признак переполнения или нет. S>Это в каких конкретно компиляторах? Или вы имеете в виду опции "отключить warning при возможном переполнении"?
В рантайм warning-ов не бывает, зато бывают исключения. А компиляторы? — все популярные.
S>В С# рекомендую курить ключевое слово checked.
OMG детсад. Я кажется начинаю понимать, откуда этот апломб... когда вокруг все кажутся гвоздями...
Был спрошен пример "менее удачных языков", и заранее приведен ответ. Ну чтобы итерации не растягивать. И это таки рантайм-детектирование — лажа, если честно. Да, на уровне файла можно задать это и для С++, т.е. не на уровне всей программы... В любом случае, останется только программу аккуратно закрыть и извиниться перед юзером... Только фигня это всё при наличии typedef в С++, бо можно написать обертку на любой тип и детектировать любые условия, которые твоему ограниченному checked и не снились. Бо шаблоны плюсов хорошо понимают глобальные и статические ф-ии и операторы, в отличии от генериков... Действительно полезно что-либо детектируется в статических анализаторах для C++. Есть статические анализаторы под C#, которые это же детектируют?
V>>Спасибо, просто открыл глаза... S>Пожалуйста. Вы обращайтесь, если что.
Очередной детсад. Ну это было весело, фактически повторить, что я и сам сказал выше на пару сообщений... Уже сказать бы хоть что-то, не правда ли?
А если по-делу: предпросмотром на этом сайте кто-нить займется или теперь уже никогда?
V>>Я уже объяснил, откуда потенциальное попадание в ловушку — из-за специальной попытки избежать if. S>Да неважно, откуда появилось потенциальное попадание. S>Это же был просто пример кода, который на первый взгляд кажется корректным. Не нужно высасывать из пальца историю, стоящую за этим кодом.
Почему нет? А как, по-твоему, работает операция сравнения в аппаратуре? Для операции сложения/вычитания нужен всего один запасной разряд в любой базе, в двоичной в т.ч., это следует прямо из твоей математики без всяких-яких. Проблема в другом, в том, флаги переполнения недоступны в высокоуровневом ЯП кроме как через ветвление (хотя доступно их копирование в любой регистр во многих процах)... а ветвление жутко дорого.
Можно предложить такой вариант без if
int a, b;
int64 tmp = int64(a) — b;
return int32((tmp >> 1) | (tmp & 0x1));
Но это на основе конкретного двоичного представления. Если оно будет не таким как мы привыкли, работать не будет. Но не суть, ты пытался привести как пример одну модель, которая "не такая как другая". А это всё еще смешно выглядело, когда ты одну из ни назвал "чистой математикой", а другая какая, нечистая, что ле? Просто одна модель проще другой и всех делов. Та моя "другая" модель с шумами — она объективно существует, т.к. шум присутствует объективно в любом случае, пока не наступила тепловая смерть. Т.е. этот шум не был выдуман специально для погрешности квантования, ровно наоборот: погрешность квантования учитывается вполне объективно уже де-факто существующем аппаратом, оценивающим шум. Тоже самое в двоичном представлении чисел — это не "другая математика", это вполне проработанная модель, по которой все эффекты можно вывести на кончике пера, не ошибешься. А ошибки случаются лишь от того, что случайно (или специально) не учитывается модель целиком.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Нет никакого порядка вызова printf() внутри реализации этой ф-ии, есть только одна эта задача на своем уровне, которая понятия не имеет о вызовах других printf(). S>>Эта задача есть инструкция control flow. printf не учавствует в вычислении, в описании того что нужно получить.
V>Второе предложение можно по-русски?
Ссылаясь на определение декларативного программирования, я утверждаю что printf не описывает что нужно получить, т.к. void, ее результат есть ничто. Вместо этого printf воспроизводит побочный эффект. Т.е. вместо описания мы имеем инструкцию.
V>>>И есть некий низлежащий слой ОС. И эта задача вполне может быть выполнена без побочных эффектов на своем уровне, передавая данные "куда-то дальше"... S>>Передача данных "куда-то дальше" — это и есть императив. И нет никаких уровней побочных эффектов. Побочный эффект либо есть либо нет.
V>На уровне твоего кода его нет. Я не зря привел ф-ый язык как пример.
Извини, ты привел в пример чистый ФЯ, при этом упоминаешь haskell. Что мне намекает на то, что ты не понимаешь природу вывода в хаскеле. V>Т.е. ты никак не можешь достоверно узнать, есть он или нет, бо на твои собственные программные примитивы это никак не влияет.
В случае haskell я достоверно знаю что побочного эффекта нет. Описание main не производит побочный эффект. V>Прямо как в ф-ом языке, где состояние-то есть, но тебе оно недоступно. Да, в случае printf есть требование последовательного исполнения, задаваемого в документации в ф-ии. Для сравнения, IO в Хаскеле задается явно в контракте ф-ии, в отличие от словесной доки по printf. Считай, что императивность сама по себе является элементом декларативности.
Тут я не понял, что ты написал, и что тебе забавно.
S>>В случае хаскеля, например, ввод-вывод не делают (не выполняют). Вместо этого результатом функции main является комбинация императивных действий и вычислений. Такая комбинация получается с помощью декларативного описания, именно она является целью декларативных вычислений. Выполнение ввода-вывода остается таким образом за бортом ФЯ.
V>Э нет, за бортом ничего не остается, есть монады, задачи которых — именно образовать цепочку вычислений. Императив. И пусть это делается "чисто функциональными ср-вами" — ничего по-сути не меняется, коль нам гарантируется последовательность вычислений.
Не вижу связи между цепочкой вычислений и императивом. Композиция функций для тебя тоже императив?
S>>В сравнении с таким подходом, результатом выполнения main у C-подобных языков является int или void. И printf для вычисления этого значения не нужен.
V>При чем тут вообще main? В Хаскеле есть ввод-вывод куда угодно, в файл, сокет и т.д., вызываемые из произвольной IO ф-ии.
Ты что-то путаешь в отношении ввода-вывода хаскеля. Ввод-вывод не вызывается из произвольной функции. Или ты уже про бэкдоры типа unsafePerformIO ?
V>Я пока не увидел, чем IO монада в Хаскеле отличается от тела ф-ии printf.
Монада IO в хаскеле не производит побочный эффект, как это делает printf. V>Про State вообще молчу... эмуляция императива как оно есть.
Эмуляция императива != императив. Хаскель описывает что нужно получить на выходе main. C описывает как нужно выводить в консоль, притом что на выходе этого описания return 0 в лучшем случае.
имхо, при текущем состоянии дел: спорить о том, является ли sql — декларативным или императивным, и тоже самое про printf — это все равно: что в многоцветном мире спорить о том, является ли голубой — белым или черным, а темно-красный цвет — черным или белым...
в текущем программировании — нет чисто декларативного, или чисто императивного подхода. есть лишь большое кол-во градаций и смешиваний этих подходов.
я предлагаю измерять декларативность и императивность не в виде одного бита — либо чисто декларативный, либо чисто императивный, а в виде аналогового параметра — например, как кол-во свободы выбора, которое оставляется исполнителю при выполнении и выборе "как" (соответственно чем больше свободы выбора "как" сделать, тем больше декларативности)
тогда в sql очень много декларативности (особенно если брать sql вообще), если брать sql в применении к конкретной базе — там декларативности обычно много меньше, и уже намного подробнее расписывается — как будет выполнена та или иная конструкция, могут даже появляться hint-ы, которые позволяют управлять тонкостями как.
в printf декларативность есть (хоть и не очень много), даже отчасти больше чем в std::cout.
контракт printf, например, не оговаривает в каком порядке параметры будут переводиться в строки, и оставляет эту свободу самому printf и т.д.
также отмечу что одни и те же конструкции могут быть больше или меньше декларативными в зависимости от мощности исполнителя.
например, возьмем конструкцию 1 + 2*3, с одной стороны — это чисто императивная конструкция, здесь четко фиксировано что за чем надо выполнить, с другой стороны — это есть и декларация, если говорится, что нам пофигу как это будет вычисляться, нам лишь важно чтобы был получен правильный ответ
Здравствуйте, DarkGray, Вы писали:
DG>я предлагаю измерять декларативность и императивность не в виде одного бита — либо чисто декларативный, либо чисто императивный, а в виде аналогового параметра — например, как кол-во свободы выбора, которое оставляется исполнителю при выполнении и выборе "как" (соответственно чем больше свободы выбора "как" сделать, тем больше декларативности)
Наличие побочного эффекта тоже аналогово выражать? Сколько побочного эффекта у printf?
DG>также отмечу что одни и те же конструкции могут быть больше или меньше декларативными в зависимости от мощности исполнителя.
DG>например, возьмем конструкцию 1 + 2*3, с одной стороны — это чисто императивная конструкция, здесь четко фиксировано что за чем надо выполнить, с другой стороны — это есть и декларация, если говорится, что нам пофигу как это будет вычисляться, нам лишь важно чтобы был получен правильный ответ
Стало интересно, какое именно определение императивности ты используешь. самопальное?
S>Наличие побочного эффекта тоже аналогово выражать?
я против черно-белого подхода, потому что он создает слабую базу для конструктивного решения задач.
и за использование широкой палитры при формировании суждений.
при обсуждении побочных эффектов: кроме двух крайностей — функция без side-effects, функция с side-effects, стоит еще выделить категории: побочный эффект, который является частью достигаемого результата, и побочный эффект, не являющийся частью достигаемого результата.
так же еще можно выделить категории: побочный эффект на который заложился автора кода; так и побочный эффект, который просто происходит.
если же речь зашла про монады, то стоит еще добавить такие категории, как побочный эффект, понимаемый ЯП, и не понимаемый, а так же зафиксированы ли программистом ожидания побочных эффектов для ЯП, или нет.
и вот в этой палитре уже можно конструктивно обсуждать: что есть полезно, что не полезно; что можно улучшить, а что нет.
S> Сколько побочного эффекта у printf?
у printf-а как минимум можно выделить три побочных эффекта:
1. изменение состояния консоли (output file-а)
2. порядок изменения состояния консоли совпадает с порядком указания printf в коде
3. изменение консоли происходит до перехода к следующей команде
при появлении буферизации, параллельного выполнения, сложных вариантов output file-а и т.д. все эффекты могут выполняться нечетко
DG>>также отмечу что одни и те же конструкции могут быть больше или меньше декларативными в зависимости от мощности исполнителя.
DG>>например, возьмем конструкцию 1 + 2*3, с одной стороны — это чисто императивная конструкция, здесь четко фиксировано что за чем надо выполнить, с другой стороны — это есть и декларация, если говорится, что нам пофигу как это будет вычисляться, нам лишь важно чтобы был получен правильный ответ S>Стало интересно, какое именно определение императивности ты используешь. самопальное?
можно взять первое же с вики
Императи́вное программи́рование — это парадигма программирования, которая, в отличие от декларативного программирования, описывает процесс вычисления в виде инструкций, изменяющих состояние программы.
соответственно, если исполнитель понимает конструкцию "1 + 2 * 3" буквально, как изменение своего состояния: отранслируй с учетом приоритетов операций в маш. код и последовательно выполни маш. код, то это императивная запись.
если же исполнитель — это понимает как "выполни как хочешь, но дай правильный результат этой конструкции", то это уже декларация.
отчасти это лучше видно на конструкции (1, 4, 2).sort(desc) — с одной стороны, исполнитель это может понимать как: создай массив, заполни его (1, 4, 2), вызови для массива функцию sort с параметром desc — и это императивный подход,
с другой стороны — исполнитель это может понимать как: необходимо переставить элементы (1, 4, 2) так, чтобы каждый следующий был меньше предыдущего — а это уже чисто декларативный подход.
если вернуться к sql там все тоже самое:
конструкция select name from users order by name может считаться императивной: найди таблицу users, выбери записи по индексу по полю name (или отсортируй), и верни только значения поля name.
а может в декларативной: дай в отсортированном виде значения поля name из таблицы users.
S>>Наличие побочного эффекта тоже аналогово выражать?
DG>я против черно-белого подхода, потому что он создает слабую базу для конструктивного решения задач. DG>и за использование широкой палитры при формировании суждений.
Это я уже понял, но не оценил.
DG>при обсуждении побочных эффектов: кроме двух крайностей — функция без side-effects, функция с side-effects, стоит еще выделить категории: побочный эффект, который является частью достигаемого результата, и побочный эффект, не являющийся частью достигаемого результата.
можно пример? Какой категории эффект от printf?
DG>так же еще можно выделить категории: побочный эффект на который заложился автора кода; так и побочный эффект, который просто происходит.
можно пример?
DG>если же речь зашла про монады, то стоит еще добавить такие категории, как побочный эффект, понимаемый ЯП, и не понимаемый, а так же зафиксированы ли программистом ожидания побочных эффектов для ЯП, или нет.
Продемонстрируй, пожалуйста, побочный эффект от монады. Только что бы он был связан именно с монадой, а не чем-то еще...
Тут по-моему надо еще добавить категории понимаем ли программистом от чего побочный эффект, или не понимаем.
DG>и вот в этой палитре уже можно конструктивно обсуждать: что есть полезно, что не полезно; что можно улучшить, а что нет.
Сначала надо разобраться, где он есть, а где его нет вовсе.
S>> Сколько побочного эффекта у printf?
DG>у printf-а как минимум можно выделить три побочных эффекта:
DG>1. изменение состояния консоли (output file-а)
+1 DG>2. порядок изменения состояния консоли совпадает с порядком указания printf в коде
Что за такой эффект и как он связан с определением побочного эффекта?
DG>3. изменение консоли происходит до перехода к следующей команде
Как это связано с определением побочного эффекта?
DG>при появлении буферизации, параллельного выполнения, сложных вариантов output file-а и т.д. все эффекты могут выполняться нечетко
По-моему у тебя нечеткое понимание побочного эффекта. Глобальное изменение состояния оно есть или нет. Четко или нечетко — это уже к качеству выполнения изменения, что мы не обсуждаем.
DG>>>например, возьмем конструкцию 1 + 2*3, с одной стороны — это чисто императивная конструкция, здесь четко фиксировано что за чем надо выполнить, с другой стороны — это есть и декларация, если говорится, что нам пофигу как это будет вычисляться, нам лишь важно чтобы был получен правильный ответ S>>Стало интересно, какое именно определение императивности ты используешь. самопальное?
DG>можно взять первое же с вики DG>
DG>Императи́вное программи́рование — это парадигма программирования, которая, в отличие от декларативного программирования, описывает процесс вычисления в виде инструкций, изменяющих состояние программы.
DG>соответственно, если исполнитель понимает конструкцию "1 + 2 * 3" буквально, как изменение своего состояния: отранслируй с учетом приоритетов операций в маш. код и последовательно выполни маш. код, то это императивная запись. DG>если же исполнитель — это понимает как "выполни как хочешь, но дай правильный результат этой конструкции", то это уже декларация.
Ну так можно дойти до того что вычислений без побочных эффектов не бывает, т.к. при вычислениях меняются содержимые регистров процессора. Только какое отношение исполнитель имеет к определению императивного программирования? Покажи связь между программой "1 + 2 * 3" и "оттранслируй, выполни".
DG>отчасти это лучше видно на конструкции (1, 4, 2).sort(desc) — с одной стороны, исполнитель это может понимать как: создай массив, заполни его (1, 4, 2), вызови для массива функцию sort с параметром desc — и это императивный подход, DG>с другой стороны — исполнитель это может понимать как: необходимо переставить элементы (1, 4, 2) так, чтобы каждый следующий был меньше предыдущего — а это уже чисто декларативный подход.
Я предлагаю ограничить осбуждение конструкциями в рамках конкретных, наперед заданных исполнителей, а не в рамках того что существует абстрактный исполнитель, который конкретную конструкцию воспринимает не так как другой.
DG>если вернуться к sql там все тоже самое: DG>конструкция select name from users order by name может считаться императивной: найди таблицу users, выбери записи по индексу по полю name (или отсортируй), и верни только значения поля name.
Ты имеешь в виду что select отсортирует таблицу по-месту, изменив тем самым содержимое таблицы? Если нет, то в чем здесь императив?
DG>а может в декларативной: дай в отсортированном виде значения поля name из таблицы users.
Здравствуйте, vdimas, Вы писали:
V>Для состояния твоей программы — несомненно одинаковы. Я ведь не зря привел пример ввода-вывода в ф-х языках.
А с каких это пор stdout перестал быть состоянием моей программы?
Вот я бы, скажем, отказался принимать у вас программу с перепутанным порядком вывода в консоль — она нарушает ТЗ.
V>Это только у нас в голове так, согласно доке по консоли.
Согласно какой доке?
V>Дык, тело сишной printf тоже не имеет никаких побочных эффектов, является полностью реентерабельной. Если бы были побочные эффекты именно внутри кода printf, она не была бы реентерабельной и многопоточной.
Совершенно необязательно. Вы опять делаете неявные предположения, которые очевидно неверны. Попробуйте формально доказать, что наличие побочных эффектов запрещает функции быть реентерабельной и многопоточной.
V>Вооот... мы дошли до цепочек вычислений в ф-ом программировании, через механизм вложенных вызовов ф-ий, мне даже не пришлось 10-й раз намекать, как для случая РА. Чем не императив? ИМХО, только точкой зрения на происходящее.
Тем, что в императиве все вычисления зависимые, если нам не удаётся доказать обратное (что в общем случае крайне трудно). А в декларативном программировании у нас есть только те зависимости, которые мы описали явно.
V>Это ес-но, речь шла о том, где заканчивается декларативное и начинается императивное. Твои побочные эффекты могут быть нам недоступны, т.е. не влиять на элементы нашей программы, примерно как в монаде IO. В чем тогда отличие якобы декларативного Хаскеля в случае этой монады, и императивной программы, которая использует только "чистые" ф-ии и процедуры, не изменяющие неявно состояния нашей программы?
Императивная программа в любом случае опирается на состояние некоторого "вычислителя". Скажем, в дотнете и яве вся семантика описана в терминах виртуальной машины и последовательности её состояний.
V>Первое предложение ты написал поторопимшись. У нас уже есть низлежащая аппаратура, которая близка по принципу работы машине Тьюринга, поэтому последовательность инструкций мы имеем как вычислительный базис. Отличие ф-ых языков от императивных в том, что ф-ые скрывают от программиста внутреннюю работу с состоянием, т.е. на уровне пользовательской программы побочных эффектов НЕТ. Я же привел printf не случайно, показав точно такой же случай, что на уровне пользовательской программы нет никаких побочных эффектов.
Что такое "уровень пользовательской программы"?
S>>В частности, можно вычислить первые N чисел Фибоначчи не за N^2, а за N, несмотря на явно рекурсивное определение этой функции.
V>Это св-во ленивости, а не ф-сти. Точно такой же эффект достижим и в императиве аж бегом, если навертишь свой некий тип Lazy<T>. Не смущает, что сам механизм ленивости основан на запоминании состояния в точке вычисления?
Это не свойство ленивости. Это возможность выполнять преобразования программы, опираясь на гарантии соответствия. Тот самый Lazy<T> применим только там, где порядок вычислений неважен. Если используемые в вычислении функции пользуются побочными эффектами, применение Lazy<> приведёт к нарушениям логики.
V>Дык, если ширина каждого слоя узлов ровно 1, то порядок будет ровно 1. Я же не зря этот пример привел, подводя к нужной мысли... но ты и сам его показал на примере цепочки printf.
Ну как можно быть таким невнимательным? В примере с printf ширина каждого слоя узлов, очевидно, 2.
И ваша мысль, к которой вы так тонко подводили, малоинтересна: да, есть такой частный случай, когда выражение представлено в виде последовательности унарных операций. Вот в нём декларативная программа однозначно сведётся к императивной. Увы, в природе такие случаи встречаются исчезающе редко.
V>В общем, я еще с самого начала предупредил, что тема иммутабельности и границ императивности — скользкая. Много холивара и условностей, а львиная доля любой императивной программы — абсолютно чиста с т.з. побочных эффектов над доступными примитивами программы. Сказать, что я заведомо определился с какой-то точкой зрения не могу. В разных спорах участвую с разных сторон. Интересны сугубо аргументы. Бо сдается мне, что прямо на сегодня в этих понятиях слишком много религиозного и зависимости от точки зрения и глубины рассмотрения происходящего. А раз так, то использовать их в кач-ве аргументов следует осторожно или не использовать вообще, предпочитая обсуждать конкретику вместо приема спора, когда вопрос пытаются отнести к некоему "классу" и выстроеному последующему док-ву на принадлежности проблемы к сему классу.
Да пожалуйста. Мне эта тема вообще неинтересна. Вы упорно отказываетесь понимать одну простую вещь: вся могучесть РА как раз в том, что она насквозь декларативна, и позволяет выполнять широкий класс оптимизаций.
V>Ага, вот где путаница, только не у меня. Для случая join мы имеем те же N, а не M (по крайней мере одна из сторон соединения просматривается целиком для любого из join).
У вас.
V>Я словесно имел ввиду, что полная формула в пределе такая: V>K1 * O(N * log N) + K2 * O(N), где K2 обычно гораздо гораздо хуже K1.
1. И куда у вас делась кардинальность второго отношения? У нас отношения с кардинальностями N и M. При этом M итерируется полностью, а среди N мы выполняем поиск.
2. Ну и где же обещанные O(N*M)? Внезапно оказалось, что никаких умножений в стоимости join уже нет.
V>Очередной бред. При чем тут "пессимистика" и логические чтения?
При том, что логические чтения превращаются в физические с вероятностью, отличной от 1. Реальный запрос никогде не будет выполнять больше физических чтений, чем логических. Поэтому если я вижу оценку в 8000 логических чтений, это не означает, что время выполнения запроса будет равно 8000 поделить на IOPS моего диска.
Cache Hit Ratio может быть достаточно высоким для того, чтобы сократить эту оценку на порядок.
V>обычно бывает ровно наоборот, зависимости для малого кол-ва данных обычно гораздо похуже, чем для асимптотики сверху. Ты этого не знаешь, поэтому порешь ерунду насчет "пессимистичности"... Ровно наоборот, оценка сверху зачастую — самая оптимистичная, т.к. для нее отбрасываются незначащие компоненты для бесконечно большого N. И эта оценка именно для логических чтений, независимо ни от какого cache hit ratio для твоих "больших размеров". Характерно, что для малого кол-ва данных тоже может случиться низкий cache hit ratio, например, если каждая страница в некоей выборке будет нужна лишь однажды, и не случится к ней того самого повторного обращения...
Я рекомендую прекратить делать предположения о том, чего я знаю, а чего нет.
V>Оба предела асимптотики, выраженной в логических чтениях, что нижний, что верхний, никак не зависят от cache hit ratio.
Правильно. Я говорю о переходе от логических чтений к физическим. V>Ты сейчас подставляешься по самое нихочу, заканчивай умничать, где не ходил еще ни разу...
Прекратите паясничать. Я вас уже столько раз ткнул носом в фактические идиотизмы, а вы по-прежнему пытаетесь понтоваться. Зачем?
V>Есть асимптотика в логических чтениях — я с ней и не спорю.
Более того, логические чтения можно рассчитать точно, а не в терминах асимптотики. И формулы будут практически такие, как мы с вами обсуждали. V>Я лишь заметил, что оценка общей сложности может выглядеть иначе и это действительно так. Тем паче, что не сказал, какая именно асимптотика, а ты уже поскакал куда-то вдаль. ИМХО, дело тут тривиально в том, что реальную сложность трудно оценить абстрактно, а можно только на конкретных соотношениях характеристик ООП и данных, поэтому даются различные виды асимптотики, например, в терминах O для логических чтений. Но т.к. размеры современной ООП таковы, что отличаются от обычных данных уже не на несколько порядков, а дай бог на один, то эти характеристики начинают влиять на реальную сложность и их тоже интересно учитывать. Вот эти мои наблюдения относительно поведения кластерных индексов — они как раз насчет вполне осязаемых соотношений данных были даны, а не "асимптотически сверху", как выдавал рекомендации ты.
Забавно вы юлите. Ваши наблюдения про N*M для сложности join — тоже насчёт "вполне осязаемых соотношений"? Или вы
S>>В этом случае у нас все коэффициенты станут фиксированными, их зависимостью от N и M можно будет пренебречь. И, конечно же, O(K1*M*logN+K2*M*logN) всё ещё сведётся к O(M*logN). Вы где вообще учились, что вам такие вещи приходится разжёвывать?
V>Позволь спросить, а ты где учился?
Новосибирский Государственный Университет. V>Фишка в том, что O(M*logN) не зависит от cache hit ratio даже для физических чтений, бо O — это ограничение асимптотики сверху. Но оценок может быть много, не обязательно оценка сверху. Ты же сам давал ссылку на что-то там по оценке сложности (хоть я и не ходил по ним, бо теорию, в отличии от, знаю неплохо, а оценка сложностей конкретных алгоритмов не интересует пока не столкнусь с ними).
Теорию вы, простите, знаете на три с минусом. Если вы стоимость join прикидываете на глаз с такими ошибками, то игнорировать шанс почитать учебники не стоит.
V>Так вот, в твоем оптимизаторе плана запросов фигурирует как раз не верхняя оценка асимптотики сложности, а именно реальная, без всяких O. Для того статистика и нужна, чтобы оперировать (пусть даже с некоторой погрешностью) заведомо известным кол-вом данных.
Конечно реальная, без всяких О.
V>Наблюдения — это объективная реальность.
Зато их интерпретация у вас не лучше, чем в анекдоте про Василия Ивановича, Петьку, и таракана.
V>Боюсь надо привести базу целиком, слишком много комбинаций. Не стыкуется наблюдение насчет эффективности кластерного основного ключа по относительно небольшим данным (см что я писал). Согласно твоим рекомендациям, это не должно зависеть от размеров данных вообще.
И где в моих рекомендациях было сказано, что кластерный индекс будет неэффективен для относительно небольших данных?
ваше активное сопротивление.
V>Да ладно тебе, своими "идите почитайте" ты нарываешься везде и всюду, где бы я не встречал твои посты. Заслужено получаешь в ответ. А здесь опять попытался сумничать не по теме обсуждения.
Так что ж я могу сделать, если вы не идёте и не читаете?
V>Я вижу крайне узкоспециализированный опыт и весьма оригинальные эффекты из-за этого, см начало обсуждение. Например о ненужности реляционной модели, и о прочих вредительских советах.
Где вы нашли "о ненужности реляционной модели"? Процитируйте. V>Так всегда бывает, когда сложную и объемную область изучают на примере конкретного продукта, непонимая, где и откуда растут ноги, и почему именно так.
Удивительное дело. У меня вот как раз полностью обратное впечатление.
Скажем, идея о том, что кластерный индекс требует фиксированного размера записи сама по себе может появиться только от непонимания, откуда растут ноги, и почему именно так. У меня такой идеи никогда даже не появлялось. Наверное, это оттого, что я плохо понимаю дизайн СУБД и причины, по которым принимаются те или иные решения в них. К сожалению, суровая практика показала, что мои некомпетентные идеи ближе к истине, чем ваши.
V>Осталось продемонстрировать, что ты (а) таки понял утверждение, (б) оно не верно. ИМХО, если выполнишь (а), то (б) отпадет само собой.
Отож.
V>Дать тебе ссылку на устройство связанного списка?
Ну, как только я перестану его понимать, или скажу глупость типа "стоимость вставки в связный список — это O(N)" — сразу давайте ссылку.
V>Еще раз, как именно происходит преобразование структурных формул SQL к вариантам планов запросов, которые ЗАТЕМ оцениваются оценочной ф-ей.
1. Выполняется парсинг запроса в AST
2. Выполняется преобразование AST в дерево логического плана исполнения запроса (про то, как применяется паттерн Visitor, надо рассказывать?)
3. Начинается построение физического плана запроса:
3.1. Порождаются различные версии физического плана. Они похожи на выражения РА, вот только в аргументах у них немножко другие объекты, чем отношения, и операции немножко другие, чем в РА
3.1.1. В частности, в отличие от РА, для аргументов очень важен порядок сортировки кортежей — от него зависит применимость операций
3.1.2. В отличие от РА, для операций важны применяемые алгоритмы — это влияет не только на оценку стоимости, но и на отсортированность результата
3.2. Процесс порождения не пытается построить все возможные планы. Это бы привело к слишком большим затратам на оптимизацию. Применяются как эвристические методы отсечения, так и основанные на оценках стоимости планов.
3.3. Как только оптимизатор найдёт приемлемый физический план выполнения (по оценкам), он передаёт план на исполнение.
Вы, пытаясь доказать свои заблуждения, выделяете фазу генерации вариантов планов запросов в отдельный этап. Ок, даже если бы это было так, всё равно РА было бы недостаточно. Я вам с самого начала говорил — то, что там применяется, только похоже на РА. Основы, несомненно, те же. Однако, используются расширения РА, что вы упорно отказываетесь признать. Если bookmark lookup и можно заменить на операцию join, если добавить к таблице и к индексу "невидимый" атрибут RID, то для операции sort никакого аналога в РА найти не удастся.
V>И таки частично ты прав, но скорее случайно, чем преднамеренно.
О, конечно. Я вообще всё время случайно оказываюсь прав, а вы преднамеренно ошибаетесь.
V>Действительно, при переборе планов запросов некоторые ветки перебора могут отсекаться довольно рано, но это было бы известно тебе и так, если бы ты понимал, как именно эти планы строятся по выражениям SQL. И да, в твоей ссылке такой информации нет.
Это потому, что вы проигнорировали ссылку на Гарсиа-Молина.
S>>Покажите мне, где эта информация есть на уровне реляционной модели. В реляционной модели понятие "отношения" достаточно чётко определено, и что там есть, и чего нету, написано очень подробно. V>Это зависимости. См. что есть реляционная модель.
Угу. Вот только в реляционной модели зависимости — это некоторые факты, которые можно вычислить. А не свойства отношений, хранимые в некоторой форме.
V>Это всего лишь атрибуты физической модели, непонятно, почему к ним неприменимы наработки РА. Это все делал товарищ Кодд, разрабатывал реализацию таблиц, индексов, операций по ним и т.д., так же разрабатывал теоретический аппарат ко всей этой кухне... прихоти ради, если тебя послушать...
Да почему прихоти ради? Я же вам объясняю: РА (и РМ) составляют основу реальных теорий, применяемых в СУБД. Точно так же, как ТФКП не опровергает арифметику. V>Скука.
Это вначале скука. А когда начнёте разбираться в том, как всё работает, становится интересно.
V>В прошлый раз ты читал невнимательно. Вплоть до 2000 серьезно использовался MS SQL, начиная с шестерки.
V>Давай прежде посмотрим, как работает memory mapped file, а потом будем делать выводы.
Куда именно вы предлагаете посмотреть?
V>Не все-равно в затратах копирования данных во внутренний кеш операционки.
Вы опять ту же песню на новый лад. Ок, давайте сравним затраты времени на копирование 64кб данных в памяти и запись 64кб на диск.
Как вы думаете, каково будет соотношение Thdd/Tram?
V>К тому же, в случае memory mapped file мы даем операционной системе решать, как ей лучше сбрасывать данные, а лучше драйвера ввода-вывода все-равно никто не знает.
Ну, если, конечно, нас не интересует целостность данных — то да, таки драйвер ввода-вывода рулит.
У MS Access всю жизнь была, скажем так, весьма примитивная recovery model. Поэтому можно, наверное, было некоторые решения отдать на откуп драйверу ввода-вывода.
V>В принципе, там суть не в IOPS, разумеется, а в том, что сервер, в отличие от ОС, знает, когда у него конец транзакции, поэтому использует копии страниц кеша, а не пользует память кеша страниц ОС напрямую, как в случае memory mapped file. Твои экстенты — они сугубо для уменьшения кол-ва дорогостоящих операций ввода/вывода, чтобы копировать за раз больше страниц... Но не на диск, разумеется, бо это не серверу решать (вот почему Oracle давно уже разраобтал свою файловую систему, чтобы держать всё под конторлем), а для того лишь, чтобы уменьшить кол-во системных вызовов, каждый из которых относительно дорогой (даже холостой вызов этого последовательного АПИ ввода-вывода стоит единицы микросекунд).
О да. Действительно. Единицы микросекунд мы экономим там, где сам вызов стоит миллисекунды. Кто бы мог подумать.
"Мои екстенты" были, естественно, применены для оптимизации алгоритма поиска свободных страниц при размещении. Ну и для того, чтобы повысить шансы на последовательное чтение — мы это уже обсуждали.
V>И кстати, IOPS на SSD-массивах скоро будет уже под миллионы и выше, при том, что пропускная способность DMA ограничена, так что тебе стоит пересмотреть свои представления. V>http://www.ixbt.com/news/hard/index.shtml?15/38/75
Ок, интересные новости. Это, несомненно, повлияет на дизайн СУБД в ближайшие лет 10. Тем не менее, общие соображения останутся прежними. И мои представления легко пересмотреть — потому что они хорошо структурированы Я заменю в них маленький кусочек, и всё будет в порядке. А вот вам придётся ставить заново все эксперименты — или выбросить накопленный опыт на помойку.
V>Основная фишка memory-mapped file в том, что в этом случае мы имеем меньше слоев IO, чем при последовательном способе, т.е. банально меньше копируется данных м/у дисковым кешем операционной системы и нашими буферами (страницами). Я уверен, что в MS SQL будет пересмотрен способ работы со страницами в ближайших версиях, бо сейчас их способ уже малость архаика.
Можно подумать, memory mapped files были придуманы недавно.
V>Я думаю, это ты не способен адекватно воспринимать информацию. Тут я лишь подстраховался на случай возможных спекуляций, что таки MS SQL где-то использует упомянутую технологию. А что спекулировать навязчиво по какой-нить теме ты способен бесконечно — я это уже видел, в вопросе последовательности операций в РА.
Зачем тогда вы упомянули про журнал и транзакционность?
V>Я знаю стоимость внешней сортировки уже более 20 лет как. Да, поленился в 1000-й посмотреть, потому что в верхнем пределе, том самом, которое при O, оно не может быть меньше.
V>Объединять составляющие в одну формулу я бы не стал. Во-первых, для асимптотики в терминах O все-равно стоит оставить самый быстрорастущий компонент... вот из-за этого и не стал бы... учитывая, что операция записи зачастую на порядок дороже операции чтения, объединять в одну оценку можно только в сферическом вакууме. Т.е. для реальных оценок при таких катастрофически разных К асимптотика O слишком грубая.
Ок, давайте откажемся от асимптотических оценок в терминах O.
S>>Ок, если вам хочется отбросить младшие члены ряда — пусть будет O(N). Несортированная сторона Join даст ещё M. Итого, имеем линейную асимптотику — O(N+M). S>>А вы, помнится, пугали меня O(N*M). Почувствуйте разницу.
V>Пффф, по кругу... Тебе осталось показать, что запись результата мощности O(N*M) будет дешевле сортировки одной из компонент.
Ну откуда же у нас взялось N*M в результате, если мы выполняем join по равенству атрибута?
V>В рантайм warning-ов не бывает, зато бывают исключения. А компиляторы? — все популярные.
Вас не затруднит привести опции компилятора, которые заставляют его выбрасывать исключения при целом переполнении для gcc и msvc?
V>А если по-делу: предпросмотром на этом сайте кто-нить займется или теперь уже никогда?
Вы зачем это у меня спрашиваете?
V>Но это на основе конкретного двоичного представления. Если оно будет не таким как мы привыкли, работать не будет. Но не суть, ты пытался привести как пример одну модель, которая "не такая как другая". А это всё еще смешно выглядело, когда ты одну из ни назвал "чистой математикой", а другая какая, нечистая, что ле? Просто одна модель проще другой и всех делов.
Совершенно верно. Зачем же вы продолжаете спорить? Одной рукой вы признаёте наличие двух (и более) моделей; одновременно с этим другой рукой упорно отрицаете наличие границы между ними. Получается, даже простейшие вещи на современных ЯП нельзя писать, основываясь на предположениях школьной арифметики относительно поведения целых чисел.
Это примерно соответствует вашей позиции про то, что "нужно изучать нижележащую платформу", несмотря на то, что вы думаете, что я с этим несогласен.
А на самом деле я несогласен с тем, чтобы склеивать в одну кучу модель школьной арифметики и модель чисел ограниченной разрядности.
V>Та моя "другая" модель с шумами — она объективно существует, т.к. шум присутствует объективно в любом случае, пока не наступила тепловая смерть. Т.е. этот шум не был выдуман специально для погрешности квантования, ровно наоборот: погрешность квантования учитывается вполне объективно уже де-факто существующем аппаратом, оценивающим шум. Тоже самое в двоичном представлении чисел — это не "другая математика", это вполне проработанная модель, по которой все эффекты можно вывести на кончике пера, не ошибешься. А ошибки случаются лишь от того, что случайно (или специально) не учитывается модель целиком.
Ошибки случаются оттого, что свойства одной модели слепо переносятся на другую модель. Ну, примерно как оценки свойств ISAM-модели переносятся на модель кластерных индексов. Из-за этого возникают предположения типа "вставка в кластерный индекс требует O(N) записей на диск", и принимаются неверные архитектурные решения.
И вот тут ключ к успеху — понимать, какие свойства относятся к чему. К примеру, "использование более одного индекса с низкой селективностью при поиске в одной таблице дороже, чем сочетание index seek с bookmark lookup и filter" как правило работает в случае хеш-индексов и btree-индексов. А вот для случая bitmap-индексов это полностью неверно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, samius, Вы писали: S>Если она не имеет побочных эффектов, значит в консоли ничего не должно измениться. Вывод в консоль есть побочный эффект. см (*). Даже если значение Console, возвращаемое printf, полностью инкапсулирует "состояние консоли", все равно где-то должна остаться информация о том что нынче актуально состояние консоли, описанное именно в последнем экземпляре. И обновление этого знания будет являться побочным эффектом.
Ну, я, возможно, фантазирую, но пока что я не вижу неотъемлемой необходимости обновления этого знания — равно как и понятия "нынче".
Идея примерно такая: вот, допустим, у нас есть некоторая Функциональная Программа. Она, собственно, сводится к одной мега-функции (скажем, Main) которая отображает вход на выход.
Эта функция написана некоторым "декларативным" способом — т.е. в виде композиции некоторого набора других функций.
Никакого "состояния" нет.
Предположим теперь, что у нас в параметры и результаты этой функции входит некоторая структура Console, которая представляет, скажем, недо-стек строк. Т.е. pop из этого стека нельзя, можно только push, при помощи функции Console println(Console c, string s).
И вот эту структуру Console мы протаскиваем во все вызовы всех функций, начиная с Main:
Console stdout = Main(emptyConsole, input);
Внутри Main могут быть всякие ветвления, рекурсия, и прочее. Каждая из функций может чего-то записывать в консоль (скажем, отладочный вывод).
Благодаря отсутствию побочных эффектов, порядок вычисления разных веток нам не важен. В том числе, параллельно могут существовать несколько версий консоли, отличающихся содержанием.
К окончанию программы у нас останется ровно одна версия консоли — та, которая вошла в результат.
Её мы и будем трактовать как "настоящую"
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
нам может быть важен порядок их вывода, и тогда их необходимо связать через одну монаду (или на пальцах: необходимо сказать явно ЯП, что порядок этих операций связан)
print("x1") >>= print("x2")
или это можно записать как (это ближе к языку Clean, где взаимодействие с внешним миром обрабатываются без монад)
World world1 = ..;
World world2 = world1 + print("x1");
World world3 = world2 + print("x2");
но нам порядок вызова может быть не важен, и тогда это
World world1 = ..;
World world1_1 = world1 + print("x1");
World world1_2 = world1 + print("x2");
World world2 = last(world1_1, world1_2);
Sinclair говорил про второй вариант. при логировании нам как раз не важен порядок вывода, нам лишь важно, что бы он осуществлялся вместе с выполнением самого кода.
S>По-моему у тебя нечеткое понимание побочного эффекта. Глобальное изменение состояния оно есть или нет.
опять ты хочешь поделить мир лишь на два полюса: глобально или локально. в реальном мире нет таких полюсов: есть лишь менее/более локально (более/менее глобально).
например, функция IEnumerable OrderBy(IEnumerable, Func) несмотря на то, что она с одной стороны чисто функциональая, имеет побочный эффект — если она меняет состояние порядка одинаковых элементов внутри результирующей последовательности.
и соответственно, не смотря на то, что функция чисто функциональная по определению — результат выражения зависит от истории применения orderby-ев к последовательности
Здравствуйте, DarkGray, Вы писали:
DG>возьмем две операции вывода на консоль: DG>
DG>print("x1");
DG>print("x2");
DG>
DG>нам может быть важен порядок их вывода, и тогда их необходимо связать через одну монаду (или на пальцах: необходимо сказать явно ЯП, что порядок этих операций связан) DG>
DG>print("x1") >>= print("x2")
DG>
Монада здесь нужна постольку поскольку ввод-вывод в хаскеле упрятан в тип IO a, разматчить который нельзя, и единственный способ манипулирования им — монадные операции. Если бы хаскель имел функцию print с мгновенным побочным эффектом, то порядок вывода можно было бы обеспечить просто передачей параметром print результата предыдущего print:
print("x2", print("x1", initialConsole))
И если бы тип IO a был не параметризован типом a, а был бы просто IO без a, тогда и монадой его связать было бы нельзя.
DG>или это можно записать как (это ближе к языку Clean, где взаимодействие с внешним миром обрабатываются без монад) DG>
Я не знаком с клином, но полагаю что как и хаскель, он выкинет эти вычисления, если за ними ничего нет, т.е. если world2 и world3 не используются более. Соответственно вызовов print не будет.
DG>но нам порядок вызова может быть не важен, и тогда это DG>
Если допустить что world2 где-то используется и last возвращает последнюю версию мира, то как я полагаю, в world2 мы получим либо "x1" либо "x2". Т.е. часть вывода пропадет.
DG>Sinclair говорил про второй вариант. при логировании нам как раз не важен порядок вывода, нам лишь важно, что бы он осуществлялся вместе с выполнением самого кода.
Еще при логировании важно ничего не терять. А функция last, судя по названию, не делает merge.
Здравствуйте, DarkGray, Вы писали:
S>>По-моему у тебя нечеткое понимание побочного эффекта. Глобальное изменение состояния оно есть или нет.
DG>опять ты хочешь поделить мир лишь на два полюса: глобально или локально. в реальном мире нет таких полюсов: есть лишь менее/более локально (более/менее глобально). DG>например, функция IEnumerable OrderBy(IEnumerable, Func) несмотря на то, что она с одной стороны чисто функциональая, имеет побочный эффект — если она меняет состояние порядка одинаковых элементов внутри результирующей последовательности.
Внутри результирующей последовательности OrderBy может менять что угодно. Внутри исходной — нет.
Между делом, у тебя опять что-то с определениями. Определение чистой функции не допускает побочные эффекты. Т.е. чистая функция не может обладать побочными эффектами по определению. У тебя же она и чистая с одной стороны, и с побочным эффектом с другой.
DG>и соответственно, не смотря на то, что функция чисто функциональная по определению — результат выражения зависит от истории применения orderby-ев к последовательности
А разве кто-то утверждал что результат применения чистых по определению функций не должен зависить от последовательности их применения?
S>Я не знаком с клином, но полагаю что как и хаскель, он выкинет эти вычисления, если за ними ничего нет, т.е. если world2 и world3 не используются более. Соответственно вызовов print не будет.
да, так и будет.
поэтому и последующие операции необходимо зацепить на world, при этом опять есть выбор: цеплять на последнее состояние мира или на более раннее, а потом объединять несколько веток. в первом случае, мы говорим, что операции должны делаться обязательно в этом порядке, во втором случае — что в произвольном порядке
S>Если допустить что world2 где-то используется и last возвращает последнюю версию мира, то как я полагаю, в world2 мы получим либо "x1" либо "x2". Т.е. часть вывода пропадет.
часть вывода не может пропасть, потому что вывод хранится во внешнем мире (а не внутри World).
пропасть может лишь код, который этот вывод делает: компилятор может решить что часть кода можно выкинуть, потому что она не используется.
если last определен как
World last(World world1, World world2)
{
if (world1.lastChangeTick < world2.lastChangeTick)
return world2;
return world1;
}
то компилятор не может выкинуть ни одну из веток
DG>>Sinclair говорил про второй вариант. при логировании нам как раз не важен порядок вывода, нам лишь важно, что бы он осуществлялся вместе с выполнением самого кода. S>Еще при логировании важно ничего не терять. А функция last, судя по названию, не делает merge.
World — это фиктивный тип (так же как монады IO, Maybe), который ничего не хранит. даже lastchangetick является фиктивной переменной уровня компиляции (или в терминах Clean это сорт)
тип World лишь нужен для того, чтобы показать какая строка кода от какой другой строки кода зависит, если это не понятно
явно на основе зависимости по результату.
DG>>и соответственно, не смотря на то, что функция чисто функциональная по определению — результат выражения зависит от истории применения orderby-ев к последовательности S>А разве кто-то утверждал что результат применения чистых по определению функций не должен зависить от последовательности их применения?
утверждается, что Referential transparency функцию можно заменить на ее результат.
order-by, меняющий одинаковые значения нельзя заменить на ее результат, потому что неизвестно как именно она меняет одинаковые параметры.
например:
((key:2,value:1), (key:1, value:3), (key:1,value:2)).order-by(pair => pair.key) нельзя заменить на результат.
потому что непонятно на какой результат менять на:
при этом пока всё данные явно известны на этапе компиляции, это не составляет серьезной проблемы: можно тупо на этапе компиляции вызвать order-by и подставить что она вернет.
проблемы начинаются, если на этапе компиляции данные известны лишь частично.
например: про исходную последовательность всё известно на этапе компиляции, кроме значений A (но известно, что оно больше 2) и B (про которое известно, только его тип: int)
имея знание на этапе компиляции, что A > 2 вроде можно order-by выкинуть из runtime-а и отсортировать сразу на этапе компиляции, но из-за того, что неизвестно (нельзя предсказать) как именно order-by меняет элементы с одинаковыми значениями, то order-by нельзя заменить на результат.
Здравствуйте, DarkGray, Вы писали:
S>>Я не знаком с клином, но полагаю что как и хаскель, он выкинет эти вычисления, если за ними ничего нет, т.е. если world2 и world3 не используются более. Соответственно вызовов print не будет.
DG>да, так и будет. DG>поэтому и последующие операции необходимо зацепить на world, при этом опять есть выбор: цеплять на последнее состояние мира или на более раннее, а потом объединять несколько веток. в первом случае, мы говорим, что операции должны делаться обязательно в этом порядке, во втором случае — что в произвольном порядке
S>>Если допустить что world2 где-то используется и last возвращает последнюю версию мира, то как я полагаю, в world2 мы получим либо "x1" либо "x2". Т.е. часть вывода пропадет.
DG>часть вывода не может пропасть, потому что вывод хранится во внешнем мире (а не внутри World). DG>пропасть может лишь код, который этот вывод делает: компилятор может решить что часть кода можно выкинуть, потому что она не используется.
Sinclair писал о другом подходе:
Благодаря отсутствию побочных эффектов, порядок вычисления разных веток нам не важен. В том числе, параллельно могут существовать несколько версий консоли, отличающихся содержанием.
К окончанию программы у нас останется ровно одна версия консоли — та, которая вошла в результат.
Отсутствие побочных эффектов говорит о том что вывод не хранится во внешнем мире, а хранится в экземпляре консоли.
DG>если last определен как DG>
DG>World last(World world1, World world2)
DG>{
DG> if (world1.lastChangeTick < world2.lastChangeTick)
DG> return world2;
DG> return world1;
DG>}
DG>
DG>то компилятор не может выкинуть ни одну из веток
Т.е. printf у тебя еще и недетерминированная?
S>>Еще при логировании важно ничего не терять. А функция last, судя по названию, не делает merge.
DG>World — это фиктивный тип (так же как монады IO, Maybe), который ничего не хранит. даже lastchangetick является фиктивной переменной уровня компиляции (или в терминах Clean это сорт)
Что значит фиктивный тип так же как и монады IO, Maybe? IO и Maybe очень даже хранят кое-что.
Да и про Clean, мне кажется что что-то не так. Вывод Clean-а заточен на уникальные типы, а две версии World-а явно противоречат уникальности.
DG>тип World лишь нужен для того, чтобы показать какая строка кода от какой другой строки кода зависит, если это не понятно DG>явно на основе зависимости по результату.
если взять stable-sort, то конечно — понятно. у нее нет побочных эффектов.
DG>>при этом пока всё данные явно известны на этапе компиляции, это не составляет серьезной проблемы: можно тупо на этапе компиляции вызвать order-by и подставить что она вернет. DG>>проблемы начинаются, если на этапе компиляции данные известны лишь частично. S>Опять выдумываешь. Referential transparency не требует того что бы данные были известны на этапе компиляции.
я говорил о другом, что если referential transparency применить к частично-известным (на этапе компиляции) данным, то побочные эффекты начинают проявляться даже в чистых функциях
In computer science, a function or expression is said to have a side effect if, in addition to returning a value, it also modifies some state or has an observable interaction with calling functions or the outside world.
Стабильность сортировки перпендикулярна побочным эффектам. Побочные эффекты — перпендикулярны возвращаемому результату функции. Пусть даже будет функция, которая с помощью rnd перемешивает исходную последовательность. Если она возвращает новую последовательность и ничего не меняет в обозримом окружении, то она не будет иметь побочных эффектов. В свою очередь стабильная сортировка по месту будет иметь побочный эффект.
S>>Опять выдумываешь. Referential transparency не требует того что бы данные были известны на этапе компиляции.
DG>я говорил о другом, что если referential transparency применить к частично-известным (на этапе компиляции) данным, то побочные эффекты начинают проявляться даже в чистых функциях
Побочные эффекты не могут проявляться в чистых функциях по определению чистой функции. http://en.wikipedia.org/wiki/Pure_function
In computer programming, a function may be described as pure if both these statements about the function hold:
The function always evaluates the same result value given the same argument value(s). The function result value cannot depend on any hidden information or state that may change as program execution proceeds or between different executions of the program, nor can it depend on any external input from I/O devices.
Evaluation of the result does not cause any semantically observable side effect or output, such as mutation of mutable objects or output to I/O devices.
Полагаю дело в том, что нестабильность сортировки ты принимаешь за побочный эффект. Это не так (см определение побочного эффекта). Нестабильность сортировки может (а может и нет) нарушать условие детерминированности, при случае если порядок элементов с равными ключами выбирается случайно. Определение детерминированности можешь поглядеть в первом пункте списка определения чистой функции (выше).
ты постоянно задачи подгоняешь под определения. хотя все наоборот — определения вводятся для того, чтобы решать задачи.
Есть задача — уметь вызывать только те куски кода, которые нужны для получения результата.
Эта задача, в первую очередь, исследовалась в рамках ФЯ для простых данных, и были введены такие понятия как side-effect, referential-transparency и т.д., которые мешают или помогают решать исходную задачу.
Но эта же задача возникает, как для сложных данных (например, частично-известных), так и для других парадигм (например, ООП) — при этом понятия side-effect, referential-transparency остаются по смыслу теми же самыми, плывут лишь детали.
но об этом, к сожалению, букварей уже не издают.
S>>Ты ведь где-то поднабрался истинного смысла? А все остальные юзают определения по-старинке, без конструктивизма. Займись изданием букваря, что-ли. Ну или дай свои определения тем терминам, что ты используешь. А те что в википедии — они не про то, о чем ты хочешь поведать.
DG>развешивание ярлыков, и выяснение при каких условиях темно-красный можно называть черным, а голубой — белым — это не ко мне, это к википедии, в букварь и т.д. DG>я готов поговорить, какие явления есть (а не определения), при каких условиях они проявляются, как они помогают (или мешают) решать те или иные задачи.
Ты даешь своим явлениям названия, значение которых строго определено и предназначено для другого.
DG>есть явление "побочный эффект" которое мешает решать ряд задач при трансформации кода.
А есть термин "побочный эффект", значение которого дано в определении. С твоим явлением ничего общего.
DG>примеры которые показывают это явление — я привел, если ты имея эти примеры и определение из википедии не можешь восстановить у себя в голове образ этого явления, то задай вопросы об этом — это конструктивный разговор.
Не могу, т.к. твое явление "побочный эффект" вполне себе уживается с твоим явлением "чистая функция". Но образы, которые у меня в голове соответстуют определениям, не позволяют объяснить сосуществование чистой функции с побочным эффектом согласно определениям же.
DG>а разговоры о терминах — это всегда деструктивный разговор, не создающий нового знания.
Деструктивный разговор — это употребление общеизвестных терминов в недоступном для собеседника смысле. Я просто не пойму о чем ты разговариваешь. Слова знакомы, а суть противоречит тому что я знаю. Какого разговора ты хочешь без согласования терминов? О чем? Ты будешь говорить о своем, а я недоумевать, как такое возможно, думая о совершенно другом?
Если хочешь, что бы тебя понимали, нужно договориться с терминами.
Здравствуйте, samius, Вы писали:
V>>Второе предложение можно по-русски? S>Ссылаясь на определение декларативного программирования, я утверждаю что printf не описывает что нужно получить, т.к. void, ее результат есть ничто. Вместо этого printf воспроизводит побочный эффект. Т.е. вместо описания мы имеем инструкцию.
А что, сигнатура ф-ии уже является полноценной декларацией? Вовсе нет, сигнатура в ФЯ лишь объявляет контракт, и то, лишь с самыми зачатками программирования в ограничениях. (Пролог в этом плане всяко мощнее.) И ввиду слабости и зачаточности этой техники нифига непонятно, что же надо получить в ф-ии int -> int*int, например... Т.е. аннотация типов есть, а какая м/у аргументами и результатами связь — непонятно...
V>>На уровне твоего кода его нет. Я не зря привел ф-ый язык как пример. S>Извини, ты привел в пример чистый ФЯ, при этом упоминаешь haskell. Что мне намекает на то, что ты не понимаешь природу вывода в хаскеле.
Ну поясни "природу", как ты понимаешь. Я понимаю как оно определено в этом языке и какие ограничения накладывает, что-то еще? Я как-то делал замечания, что ф-ый подход хорош там где нам надо данные вычислять и не очень хорош когда эти вычисленные данные потом надо куда-то девать. А девать их куда-то рано или поздно придется. Т.е. абсолютно любой ф-ий язык должен иметь связь с внешним миром, чтобы быть хоть немного полезен именно как язык программирования.
V>>Т.е. ты никак не можешь достоверно узнать, есть он или нет, бо на твои собственные программные примитивы это никак не влияет. S>В случае haskell я достоверно знаю что побочного эффекта нет. Описание main не производит побочный эффект.
Достоверно знать можно разными путями, начнем с того что. Аннотация типов и ф-ой чистоты — лишь один из способов. Компилятор всяко больше может знать, выведя все зависимости.
S>>>В случае хаскеля, например, ввод-вывод не делают (не выполняют). Вместо этого результатом функции main является комбинация императивных действий и вычислений. Такая комбинация получается с помощью декларативного описания, именно она является целью декларативных вычислений. Выполнение ввода-вывода остается таким образом за бортом ФЯ.
V>>Э нет, за бортом ничего не остается, есть монады, задачи которых — именно образовать цепочку вычислений. Императив. И пусть это делается "чисто функциональными ср-вами" — ничего по-сути не меняется, коль нам гарантируется последовательность вычислений. S>Не вижу связи между цепочкой вычислений и императивом. Композиция функций для тебя тоже императив?
Банально инструмент для оного. Этим инструментом явно описывается такая фундаментальная вещь, как детерминированный поток исполнения, что и требовалось. Не всё ли равно, какой инструмент? Аргументы насчет "явных" зависимостей — немного слабоваты. Мы же вполне можем писать без глобальных переменных в том же ООП. Ведь состояние вполне может быть локально, типа переменных стека или переменных объекта. В этих случаях замыкание или void-методы можно рассматривать как принимающие и возвращающие локальный контекст, в котором объявлены (оно так и есть технически с разной степенью подробности).
S>>>В сравнении с таким подходом, результатом выполнения main у C-подобных языков является int или void. И printf для вычисления этого значения не нужен.
V>>При чем тут вообще main? В Хаскеле есть ввод-вывод куда угодно, в файл, сокет и т.д., вызываемые из произвольной IO ф-ии. S>Ты что-то путаешь в отношении ввода-вывода хаскеля. Ввод-вывод не вызывается из произвольной функции. Или ты уже про бэкдоры типа unsafePerformIO ?
Нет, я про любые IO ф-ии. То, что main организует IO — непринципиально, ведь может же быть возможность, интероперабельности кода на Хаскеле с другими языками (подрбно не копал, но вроде есть проекты для хаскеля генерации то в байткоды, то код на других языках), т.е. какая разница, кто именно запускает IO — main или другая "точка входа"? Хаскель был приведен лишь как пример языка, считающегося чистым функциональным для демонстрации неизбежности императивности в любой программе, целью которой является чуть больше, чем собственная компиллируемость (это я на всякий случай откидываю класс языков, используемых для док-ва теорем).
V>>Я пока не увидел, чем IO монада в Хаскеле отличается от тела ф-ии printf. S>Монада IO в хаскеле не производит побочный эффект, как это делает printf. V>>Про State вообще молчу... эмуляция императива как оно есть. S>Эмуляция императива != императив.
Дудки! Иначе эмуляцию ФП на современных императивных выч. машинах, близких по принципу работы к машине Тьюринга, нельзя было считать за ФП.
Но тут же все утверждают что "ФП существует!", и вполне согласен, хоть оно и эмулируется на самом деле. Какая фиг разница, с помощью какого инструмента воспроизводится требуемая механика, если в результате можно получить все точно такие же эффекты (например, побочные эффекты в случае State)? Простоты ради предположи, что любой метод объекта в ООП не изменяет состояние объекта, а порождает новое измененное состояние, прямо как в State. И найди после этого отличия.
S>Хаскель описывает что нужно получить на выходе main. C описывает как нужно выводить в консоль, притом что на выходе этого описания return 0 в лучшем случае.
Сорри, но это уже классика в стиле "тут смотрим, тут не смотрим". Описание в виде ограничений типов — это еще нифига не описание. Это так, легкое ограничение на то, что можно подставить внутрь этого описания. Учитывая вывод типов и прочие плюшки, т.е. даже зачастую отсутствие нотации типов в описании я могу так же прдеположить что "тип" любого локального контекста в императивной программе компилятор "выводит" вполне успешно.
На самом деле для док-ва корректности и даже вывода результата "на кончике пера" требуется вовсе не чистота, не иммутабельность (как тут считают некоторые), а гарантия локальности контекста. Т.е. гарантии того, что "кто-то" извне что-то не испортит. Мы когда-то с thesz проходились по этой теме в философии, таки сошлись на том, что в случае иммутабельности всего-навсего чуть проще любые реализации таких "доказывающих" аппаратов. Т.е. отсутствие побочных эффектов — это не обязательное требование для док-ва корретности и прочего из этой области, но достаточное. А коль так, коль есть возможность в императивном виде породить столь же корректную программу (например, с гарантией однопоточности для любого локального контекста), со всеми автовыводимыми зависимостями, то любая императивная запись программы ничем не будет отличаться от чистой ф-ой кроме как в плане требований к сложности компилятора и прочего инструментария. Кароч, одинаковая будет степень декларативности. И это даже можно будет доказать на примере модели эквивалентного ф-го преобразователя с памятью.
Здравствуйте, samius, Вы писали:
S>Вот тут-то и появляется мир с его состоянием, которое обновляется должным образом в процессе выполнения итоговой функции. Трюк в том, что это происходит за пределами программы на хаскеле.
Да нет никакого трюка. Это ты описал принцип работы ф-ого преобразователя с памятью. Он состоит из памяти и собсно ф-ии вычисления следующего состояния. Рассуждая таким же образом, императивная программа ведет себя точно так же, получает World на входе, и что-то с ним делает с помощью "сконструированной" компилятором программы. Степень декларативности тут одинаковая.
S>>Внутри Main могут быть всякие ветвления, рекурсия, и прочее. Каждая из функций может чего-то записывать в консоль (скажем, отладочный вывод). S>да, ветвления, рекурсия и прочее. Но каждая из функций, к которым обращается main, не пишет и не читает. Они возвращают функции, которые при выполнении будут писать и читать.
Да какая разница? На ф-ом языке операции над ФПВ и есть львиная доля программы.
Тем более, что в ленивом языке любая ф-ия по определению возвращает ф-ию, а не результат, которая будет работать лишь при "выполнении" (С).
S>На этапе построения результата main побочных эффектов нет.
Вообще-то есть — это сама технология ленивости. Но тебе эта "побочность" явным образом недоступна, хоть она декларируется в семантике и на нее надо полагаться.
S>Но порядок их выполнения при выполнении результирующей функции нам важен. Этот порядок обеспечивается композицией функций, из которых строится main. Они представляют собой конвейер по надругательствам над миром. Тут уже не важно, считать ли мир изменяемым, или считать что каждая функция при выполнении создает новую копию мира и где-то есть указатель на текущий мир. Важно что конвейер обеспечивает точный порядок приложения функций к миру.
О чем и речь. Используется имеющийся механизм для создания потока вычисления.
S>А в хаскеле так: к окончанию декларативной программы на хаскеле у нас появляется программа для вычислителя. Программа для вычислителя императивна и может работать с изменяющимся миром/консолью.
Все это с таким ворохом допущений... Для сравнения, программу на С++ в шаблонах тоже можно считать декларативной, порождающей целевой "вычислитель".
Здравствуйте, samius, Вы писали:
S>Здравствуйте, vdimas, Вы писали:
V>>Здравствуйте, Sinclair, Вы писали:
V>>>>есть только одна эта задача на своем уровне, которая понятия не имеет о вызовах других printf(). И есть некий низлежащий слой ОС. И эта задача вполне может быть выполнена без побочных эффектов на своем уровне, передавая данные "куда-то дальше"... S>>>Нет, она не может быть выполнена без побочных эффектов. Она целиком и полностью опирается на определённое поведение разделяемого состояния.
V>>Это только у нас в голове так, согласно доке по консоли. S>Т.е. если доку не читать, то побочных эффектов в printf не будет?
Неизвестно,зависит того, null там или другой девайс.
V>>Дык, тело сишной printf тоже не имеет никаких побочных эффектов, является полностью реентерабельной. Если бы были побочные эффекты именно внутри кода printf, она не была бы реентерабельной и многопоточной. И да, в printf таки подается FILE (просто в той перегрузке, в которой не подается, используется глобальная переменная). И отличие в Хаскеля лишь в том, что IO-тип Console не надо возвращать обратно как результат ф-ии, бо это лишь частное требование для механики монады IO, которая не нужна в C++. S>printf консоль портит? Портит. А значит побочный эффект присутствует. putChar консоль портит? Нет. Вот в этом и отличие от Хаскеля.
Это ты слишком поверхностно рассматриваешь. Давай мы распишем механику ленивости, для начала. А потом модель императивного вычислителя. И только потом будем искать разницу, а не вот так, с высоты птичьего полета да еще под удобным углом.
V>>Вооот... мы дошли до цепочек вычислений в ф-ом программировании, через механизм вложенных вызовов ф-ий, мне даже не пришлось 10-й раз намекать, как для случая РА. Чем не императив? ИМХО, только точкой зрения на происходящее. S>f(g(x)) тоже императив?
Во избежание спекуляций, без контекста и рассмотрения подробностей отвечать на это не буду. Бо я именно согласен или обсуждать вглубь, или никак вообще. Любой Тьюринг-полный язык императивен по своему определению, например Хаскель. То, что в нем есть ФВП, ленивость и иммутабельность — это лишь приятные плюшки, но не более. Неимперативным в принципе может быть только Тьюринг-неполный язык и никакой другой.
V>>Это ес-но, речь шла о том, где заканчивается декларативное и начинается императивное. Твои побочные эффекты могут быть нам недоступны, т.е. не влиять на элементы нашей программы, примерно как в монаде IO. В чем тогда отличие якобы декларативного Хаскеля в случае этой монады, и императивной программы, которая использует только "чистые" ф-ии и процедуры, не изменяющие неявно состояния нашей программы? S>В том что программа на Хаскеле описывает результат. А императивная программа описывает последовательность действий.
Нет, это тебя опять несет на высоту птичьего полета. Программа на Хаскеле для IO всегда описывает именно действия, которые будет совершать эта ф-ия. То, что любая ф-ия на самом деле возвращает ф-ию — это св-во ленивости, а не чистой ф-сти. Тут ты пытаешься всё свалить в кучу. Я видел твою "расшифровку" монады IO, но даже этого не требуется, коль IO ф-ия ленива.
V>>Первое предложение ты написал поторопимшись. У нас уже есть низлежащая аппаратура, которая близка по принципу работы машине Тьюринга, поэтому последовательность инструкций мы имеем как вычислительный базис. Отличие ф-ых языков от императивных в том, что ф-ые скрывают от программиста внутреннюю работу с состоянием, т.е. на уровне пользовательской программы побочных эффектов НЕТ. Я же привел printf не случайно, показав точно такой же случай, что на уровне пользовательской программы нет никаких побочных эффектов. Я понимаю, что тебе сразу захотелось полезть куда-то внутрь, чуть ли не до самой машины Тьюринга и показать мне, что таки состояние есть у консоли "где-то там унутрях"... но это очень толсто, коль этот случай сравнивался с точно таким же аналогичным из ФЯ... S>И зачем по-твоему вызывать из C++ printf если побочных эффектов у него нет и он ничего не возвращает/вычисляет? Почему бы его просто не выкинуть из пользовательской программы?
А почему из Хаскеля не выкидываешь? Еще раз, ТВОЯ программа не имеет доступа к этим побочным эффектам, прямо как в Хаскеле.
V>>В общем, я еще с самого начала предупредил, что тема иммутабельности и границ императивности — скользкая. Много холивара и условностей, а львиная доля любой императивной программы — абсолютно чиста с т.з. побочных эффектов над доступными примитивами программы. Сказать, что я заведомо определился с какой-то точкой зрения не могу. В разных спорах участвую с разных сторон. Интересны сугубо аргументы. Бо сдается мне, что прямо на сегодня в этих понятиях слишком много религиозного и зависимости от точки зрения и глубины рассмотрения происходящего. А раз так, то использовать их в кач-ве аргументов следует осторожно или не использовать вообще, предпочитая обсуждать конкретику вместо приема спора, когда вопрос пытаются отнести к некоему "классу" и выстроеному последующему док-ву на принадлежности проблемы к сему классу. S>Конечно, если считать printf декларативным и не имеющим побочных эффектов, а монады императивными, то тема очень скользкая. S>Давай по-маленьку. Как printf влияет на результат функции, в теле которой вызывается? Как влияет putChar из Хаскеля?
И кстате, можно не только Хаскель. Вон Эрланг торчит в разделе декларативных языков на этом сайте, можно посмотреть ввод-вывод у него — классика ф-ой композиции для целей императивности.
Здравствуйте, samius, Вы писали:
DG>>при появлении буферизации, параллельного выполнения, сложных вариантов output file-а и т.д. все эффекты могут выполняться нечетко S>По-моему у тебя нечеткое понимание побочного эффекта. Глобальное изменение состояния оно есть или нет. Четко или нечетко — это уже к качеству выполнения изменения, что мы не обсуждаем.
Во-первых, необязательно глобальное состояние (это слишком упрощено), а во-вторых — четкость изменения состояния — это архиважно (С) важно для соответствия императивной программы автоматной модели.
DG>>если же исполнитель — это понимает как "выполни как хочешь, но дай правильный результат этой конструкции", то это уже декларация. S>Ну так можно дойти до того что вычислений без побочных эффектов не бывает, т.к. при вычислениях меняются содержимые регистров процессора.
Можно ограничиться машиной Тьюринга. И да, это так, даже для любого сколь-угодно чистого ФЯ. Императивная программа является декларацией для низлежащей вычислительной модели, ничем не худшей декларацией, чем любая ф-ая программа, это можно доказать на примере эквивалентных автоматов. Собсно, именно это я изначально и постулировал.
S>Только какое отношение исполнитель имеет к определению императивного программирования? Покажи связь между программой "1 + 2 * 3" и "оттранслируй, выполни".
Эта связь подразумевается и она присутствует by design, коль речь идет о программе, а не о некоем текстовом файле для отсылки его содержимого по почте. Известно несколько техник исполнения программ, выбирай любую: компиляция, интерпретация или всякие их новомодные управляемые гибриды... выбирай не стесняйся.
DG>>отчасти это лучше видно на конструкции (1, 4, 2).sort(desc) — с одной стороны, исполнитель это может понимать как: создай массив, заполни его (1, 4, 2), вызови для массива функцию sort с параметром desc — и это императивный подход, DG>>с другой стороны — исполнитель это может понимать как: необходимо переставить элементы (1, 4, 2) так, чтобы каждый следующий был меньше предыдущего — а это уже чисто декларативный подход. S>Я предлагаю ограничить осбуждение конструкциями в рамках конкретных, наперед заданных исполнителей, а не в рамках того что существует абстрактный исполнитель, который конкретную конструкцию воспринимает не так как другой.
Фишка в том, что оба этих исполнителя на уровне машины Тьюринга будут эквивалентны. Поэтому т.з. на абстрактного "исполнителя" вообще не важна.
DG>>если вернуться к sql там все тоже самое: DG>>конструкция select name from users order by name может считаться императивной: найди таблицу users, выбери записи по индексу по полю name (или отсортируй), и верни только значения поля name. S>Ты имеешь в виду что select отсортирует таблицу по-месту, изменив тем самым содержимое таблицы? Если нет, то в чем здесь императив?
В алгоритме в терминах инструкций, очевидно:
— найди таблицу
— выбери проекцию
— отсортируй результат
И откуда ты решил, что по-месту?
DG>>а может в декларативной: дай в отсортированном виде значения поля name из таблицы users.
Хороший пример, показывающий эквивалентность декларативного определения и определения в терминах инструкций. На самом деле, на любом выбранном уровне подробностей эти определения будут эквивалентны. Они будут неэквивалентны лишь тогда, когда попытаемся приписать для любого выбранного примера разный уровень подробностей декларативному и императивному.
Здравствуйте, samius, Вы писали:
S>>>По-моему у тебя нечеткое понимание побочного эффекта. Глобальное изменение состояния оно есть или нет.
DG>>опять ты хочешь поделить мир лишь на два полюса: глобально или локально. в реальном мире нет таких полюсов: есть лишь менее/более локально (более/менее глобально). DG>>например, функция IEnumerable OrderBy(IEnumerable, Func) несмотря на то, что она с одной стороны чисто функциональая, имеет побочный эффект — если она меняет состояние порядка одинаковых элементов внутри результирующей последовательности. S>Внутри результирующей последовательности OrderBy может менять что угодно. Внутри исходной — нет. S>Между делом, у тебя опять что-то с определениями. Определение чистой функции не допускает побочные эффекты. Т.е. чистая функция не может обладать побочными эффектами по определению. У тебя же она и чистая с одной стороны, и с побочным эффектом с другой.
Ну да, например ленивость... Самый что ни на есть побочный эффект, "выпрямляющий" вычисления. Тут уже как-то обсуждалось похожая тема. Кароч, с понятием "побочный эффект" надо быть аккуратней, бо речь всегда может идти только о доступном для осязания/измерения/использования побочном эффекте, иначе можно считать что его нет. Именно так эмулируется ФП императивном вычислительном базисе, через допущения относительно видимости побочных эффектов.
DG>>и соответственно, не смотря на то, что функция чисто функциональная по определению — результат выражения зависит от истории применения orderby-ев к последовательности S>А разве кто-то утверждал что результат применения чистых по определению функций не должен зависить от последовательности их применения?
А это уже заворот на 10-й круг в этом обсуждении. Можно смело завязывать, стороны выдохлись.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Ссылаясь на определение декларативного программирования, я утверждаю что printf не описывает что нужно получить, т.к. void, ее результат есть ничто. Вместо этого printf воспроизводит побочный эффект. Т.е. вместо описания мы имеем инструкцию.
V>А что, сигнатура ф-ии уже является полноценной декларацией? Вовсе нет, сигнатура в ФЯ лишь объявляет контракт, и то, лишь с самыми зачатками программирования в ограничениях. (Пролог в этом плане всяко мощнее.) И ввиду слабости и зачаточности этой техники нифига непонятно, что же надо получить в ф-ии int -> int*int, например... Т.е. аннотация типов есть, а какая м/у аргументами и результатами связь — непонятно...
Видишь ли, когда ты вызываешь функцию не ради ее результата, ты тем самым говоришь что она тебе не для вычисления нужна, а для побочного эффекта. Хоть printf все-таки не void, а int. И зовут ее ради побочного эффекта, тем самым попадая под определение императива.
S>>Извини, ты привел в пример чистый ФЯ, при этом упоминаешь haskell. Что мне намекает на то, что ты не понимаешь природу вывода в хаскеле.
V>Ну поясни "природу", как ты понимаешь. Я понимаю как оно определено в этом языке и какие ограничения накладывает, что-то еще? Я как-то делал замечания, что ф-ый подход хорош там где нам надо данные вычислять и не очень хорош когда эти вычисленные данные потом надо куда-то девать. А девать их куда-то рано или поздно придется. Т.е. абсолютно любой ф-ий язык должен иметь связь с внешним миром, чтобы быть хоть немного полезен именно как язык программирования.
Я объяснял природу как я ее понимаю. В двух словах — программа на хаскеле декларативно объявляет комбинацию функций (в том числе императивных). Но я уже повторяюсь. А ты мне пишешь про императивные монады. Продемонстрируй мне императивность монад в коде, покажи побочный эффект!
S>>В случае haskell я достоверно знаю что побочного эффекта нет. Описание main не производит побочный эффект.
V>Достоверно знать можно разными путями, начнем с того что. Аннотация типов и ф-ой чистоты — лишь один из способов. Компилятор всяко больше может знать, выведя все зависимости.
Ты можешь показать обнаруживаемый побочный эффект от main хаскеля? От именно самой main, а не от запуска результата, который возвращает main.
S>>Не вижу связи между цепочкой вычислений и императивом. Композиция функций для тебя тоже императив?
V>Банально инструмент для оного. Этим инструментом явно описывается такая фундаментальная вещь, как детерминированный поток исполнения, что и требовалось. Не всё ли равно, какой инструмент? Аргументы насчет "явных" зависимостей — немного слабоваты. Мы же вполне можем писать без глобальных переменных в том же ООП.
Продемонстрируй побочный эффект от композиции чистых функций.
V>Ведь состояние вполне может быть локально, типа переменных стека или переменных объекта. В этих случаях замыкание или void-методы можно рассматривать как принимающие и возвращающие локальный контекст, в котором объявлены (оно так и есть технически с разной степенью подробности).
А кто говорит о локальном состоянии? Каким образом локальное состояние может быть интерпретировано как побочный эффект вычислений?
S>>Ты что-то путаешь в отношении ввода-вывода хаскеля. Ввод-вывод не вызывается из произвольной функции. Или ты уже про бэкдоры типа unsafePerformIO ?
V>Нет, я про любые IO ф-ии. То, что main организует IO — непринципиально, ведь может же быть возможность, интероперабельности кода на Хаскеле с другими языками (подрбно не копал, но вроде есть проекты для хаскеля генерации то в байткоды, то код на других языках), т.е. какая разница, кто именно запускает IO — main или другая "точка входа"? Хаскель был приведен лишь как пример языка, считающегося чистым функциональным для демонстрации неизбежности императивности в любой программе, целью которой является чуть больше, чем собственная компиллируемость (это я на всякий случай откидываю класс языков, используемых для док-ва теорем).
Ну так продемонстрируй мне императивность функции main хаскеля. А то твоя демонстрация пока не удалась.
V>>>Я пока не увидел, чем IO монада в Хаскеле отличается от тела ф-ии printf. S>>Монада IO в хаскеле не производит побочный эффект, как это делает printf. V>>>Про State вообще молчу... эмуляция императива как оно есть. S>>Эмуляция императива != императив.
V>Дудки! Иначе эмуляцию ФП на современных императивных выч. машинах, близких по принципу работы к машине Тьюринга, нельзя было считать за ФП.
Ты видел в определении императивного программирования ссылку на изменяемость состояния вычислителя? Я нет. Речь о программе, а не о способе ее выполнения.
V>Но тут же все утверждают что "ФП существует!", и вполне согласен, хоть оно и эмулируется на самом деле. Какая фиг разница, с помощью какого инструмента воспроизводится требуемая механика, если в результате можно получить все точно такие же эффекты (например, побочные эффекты в случае State)? Простоты ради предположи, что любой метод объекта в ООП не изменяет состояние объекта, а порождает новое измененное состояние, прямо как в State. И найди после этого отличия.
Если любой метод объекта в ООП не будет изменять состояние объекта (и не только объекта, а вообще обозримого состояния), то по определению императива императива в этом объекте не будет.
S>>Хаскель описывает что нужно получить на выходе main. C описывает как нужно выводить в консоль, притом что на выходе этого описания return 0 в лучшем случае.
V>Сорри, но это уже классика в стиле "тут смотрим, тут не смотрим". Описание в виде ограничений типов — это еще нифига не описание. Это так, легкое ограничение на то, что можно подставить внутрь этого описания. Учитывая вывод типов и прочие плюшки, т.е. даже зачастую отсутствие нотации типов в описании я могу так же прдеположить что "тип" любого локального контекста в императивной программе компилятор "выводит" вполне успешно.
Причем тут ограничения типов? Покажи лучше побочный эффект от main-а хаскеля.
V>На самом деле для док-ва корректности и даже вывода результата "на кончике пера" требуется вовсе не чистота, не иммутабельность (как тут считают некоторые), а гарантия локальности контекста. Т.е. гарантии того, что "кто-то" извне что-то не испортит. Мы когда-то с thesz проходились по этой теме в философии, таки сошлись на том, что в случае иммутабельности всего-навсего чуть проще любые реализации таких "доказывающих" аппаратов. Т.е. отсутствие побочных эффектов — это не обязательное требование для док-ва корретности и прочего из этой области, но достаточное. А коль так, коль есть возможность в императивном виде породить столь же корректную программу (например, с гарантией однопоточности для любого локального контекста), со всеми автовыводимыми зависимостями, то любая императивная запись программы ничем не будет отличаться от чистой ф-ой кроме как в плане требований к сложности компилятора и прочего инструментария.
Проще, не проще — это не предмет обсуждения. Любая императивная запись ничем не будет отличаться от чистой фунциональной? Ну вот тебе printf("\n"). Покажи неотличимую чистую функциональную
V>Кароч, одинаковая будет степень декларативности. И это даже можно будет доказать на примере модели эквивалентного ф-го преобразователя с памятью.
Степень декларативности определяется по соответствию определению декларативности. Модели преобразования памяти не интересуют в контексте обсуждения декларативности. Мы обсжудаем декларативность программы, а не преобразований памяти.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Вот тут-то и появляется мир с его состоянием, которое обновляется должным образом в процессе выполнения итоговой функции. Трюк в том, что это происходит за пределами программы на хаскеле.
V>Да нет никакого трюка. Это ты описал принцип работы ф-ого преобразователя с памятью. Он состоит из памяти и собсно ф-ии вычисления следующего состояния. Рассуждая таким же образом, императивная программа ведет себя точно так же, получает World на входе, и что-то с ним делает с помощью "сконструированной" компилятором программы. Степень декларативности тут одинаковая.
Извини, но мы обсуждаем декларативность исходной программы а не сконструипрованной компилятором программы.
S>>да, ветвления, рекурсия и прочее. Но каждая из функций, к которым обращается main, не пишет и не читает. Они возвращают функции, которые при выполнении будут писать и читать.
V>Да какая разница? На ф-ом языке операции над ФПВ и есть львиная доля программы. V>Тем более, что в ленивом языке любая ф-ия по определению возвращает ф-ию, а не результат, которая будет работать лишь при "выполнении" (С).
Отлично.
S>>На этапе построения результата main побочных эффектов нет.
V>Вообще-то есть — это сама технология ленивости. Но тебе эта "побочность" явным образом недоступна, хоть она декларируется в семантике и на нее надо полагаться.
Побочность явным образом недоступна => побочного эффекта нет. См. определение побочного эффекта.
S>>Но порядок их выполнения при выполнении результирующей функции нам важен. Этот порядок обеспечивается композицией функций, из которых строится main. Они представляют собой конвейер по надругательствам над миром. Тут уже не важно, считать ли мир изменяемым, или считать что каждая функция при выполнении создает новую копию мира и где-то есть указатель на текущий мир. Важно что конвейер обеспечивает точный порядок приложения функций к миру.
V>О чем и речь. Используется имеющийся механизм для создания потока вычисления.
О чем и речь.
S>>А в хаскеле так: к окончанию декларативной программы на хаскеле у нас появляется программа для вычислителя. Программа для вычислителя императивна и может работать с изменяющимся миром/консолью.
V>Все это с таким ворохом допущений... Для сравнения, программу на С++ в шаблонах тоже можно считать декларативной, порождающей целевой "вычислитель".
Программа на шаблонах возвращает(вычисляет) вычислитель? Нет?
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Т.е. если доку не читать, то побочных эффектов в printf не будет?
V>Неизвестно,зависит того, null там или другой девайс.
Если неизвестно, то считать что их нет наивно.
V>>>Дык, тело сишной printf тоже не имеет никаких побочных эффектов, является полностью реентерабельной. Если бы были побочные эффекты именно внутри кода printf, она не была бы реентерабельной и многопоточной. И да, в printf таки подается FILE (просто в той перегрузке, в которой не подается, используется глобальная переменная). И отличие в Хаскеля лишь в том, что IO-тип Console не надо возвращать обратно как результат ф-ии, бо это лишь частное требование для механики монады IO, которая не нужна в C++. S>>printf консоль портит? Портит. А значит побочный эффект присутствует. putChar консоль портит? Нет. Вот в этом и отличие от Хаскеля.
V>Это ты слишком поверхностно рассматриваешь. Давай мы распишем механику ленивости, для начала. А потом модель императивного вычислителя. И только потом будем искать разницу, а не вот так, с высоты птичьего полета да еще под удобным углом.
Ну т.е. как в случае с существованием переменной (понятия ЯВУ) ты ищешь переменную в исполняющемся коде, так и декларативность языка ты определяешь не по конструкциям языка, а по вычислителю?
Ну что мне сказать? Скажу что я не разделяю такую позицию.
V>>>Вооот... мы дошли до цепочек вычислений в ф-ом программировании, через механизм вложенных вызовов ф-ий, мне даже не пришлось 10-й раз намекать, как для случая РА. Чем не императив? ИМХО, только точкой зрения на происходящее. S>>f(g(x)) тоже императив?
V>Во избежание спекуляций, без контекста и рассмотрения подробностей отвечать на это не буду. Бо я именно согласен или обсуждать вглубь, или никак вообще. Любой Тьюринг-полный язык императивен по своему определению, например Хаскель.
По какому определению, позволь? не по этому?
В теории вычислимости исполнитель (множество вычисляющих элементов) называется тьюринг-полным, если на нём можно реализовать любую вычислимую функцию.
Раскрой, пожалуйста, как из такой полноты вытекает императивность? Может она вытекает из возможности эмуляции функциональной машины на МТ? Мне не очевидно.
V>То, что в нем есть ФВП, ленивость и иммутабельность — это лишь приятные плюшки, но не более. Неимперативным в принципе может быть только Тьюринг-неполный язык и никакой другой.
Пруф? Или хотя бы направление рассуждений доказательства? Пока ты не доказал что хаскель императивен, я считаю его существование опровержением твоего тезиса.
S>>В том что программа на Хаскеле описывает результат. А императивная программа описывает последовательность действий.
V>Нет, это тебя опять несет на высоту птичьего полета. Программа на Хаскеле для IO всегда описывает именно действия, которые будет совершать эта ф-ия. То, что любая ф-ия на самом деле возвращает ф-ию — это св-во ленивости, а не чистой ф-сти. Тут ты пытаешься всё свалить в кучу. Я видел твою "расшифровку" монады IO, но даже этого не требуется, коль IO ф-ия ленива.
Ленивость не означает императивность, не так ли?
V>А почему из Хаскеля не выкидываешь? Еще раз, ТВОЯ программа не имеет доступа к этим побочным эффектам, прямо как в Хаскеле.
Из хаскеля я вывод не выкидываю потому как он составляющая часть результата main.
S>>Конечно, если считать printf декларативным и не имеющим побочных эффектов, а монады императивными, то тема очень скользкая. S>>Давай по-маленьку. Как printf влияет на результат функции, в теле которой вызывается? Как влияет putChar из Хаскеля?
V>Про зависимости я ответил даже не помаленьку, а сразу с заделом тут: http://www.rsdn.ru/forum/philosophy/4570092.1.aspx
V>Давай уже там.
Давай. Только я там не увидел ответа.
V>И кстате, можно не только Хаскель. Вон Эрланг торчит в разделе декларативных языков на этом сайте, можно посмотреть ввод-вывод у него — классика ф-ой композиции для целей императивности.
F# тоже торчит в разделе декларативных, так он еще и ООП, никто же не говорит что ООП стало декларативным.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
DG>>>при появлении буферизации, параллельного выполнения, сложных вариантов output file-а и т.д. все эффекты могут выполняться нечетко S>>По-моему у тебя нечеткое понимание побочного эффекта. Глобальное изменение состояния оно есть или нет. Четко или нечетко — это уже к качеству выполнения изменения, что мы не обсуждаем.
V>Во-первых, необязательно глобальное состояние (это слишком упрощено), а во-вторых — четкость изменения состояния — это архиважно (С) важно для соответствия императивной программы автоматной модели.
сложно не сложно, четко не четко — это незначительные детали в контексте проверки определения.
S>>Ну так можно дойти до того что вычислений без побочных эффектов не бывает, т.к. при вычислениях меняются содержимые регистров процессора.
V>Можно ограничиться машиной Тьюринга. И да, это так, даже для любого сколь-угодно чистого ФЯ. Императивная программа является декларацией для низлежащей вычислительной модели, ничем не худшей декларацией, чем любая ф-ая программа, это можно доказать на примере эквивалентных автоматов. Собсно, именно это я изначально и постулировал.
Мы обсуждаем императивность/декларативность программы на ЯВУ, а не низлежащего вычислителя.
S>>Только какое отношение исполнитель имеет к определению императивного программирования? Покажи связь между программой "1 + 2 * 3" и "оттранслируй, выполни".
V>Эта связь подразумевается и она присутствует by design, коль речь идет о программе, а не о некоем текстовом файле для отсылки его содержимого по почте. Известно несколько техник исполнения программ, выбирай любую: компиляция, интерпретация или всякие их новомодные управляемые гибриды... выбирай не стесняйся.
Можешь показать где в определении императивности/декларативности рассматриваются подразумеваемые связи?
S>>Я предлагаю ограничить осбуждение конструкциями в рамках конкретных, наперед заданных исполнителей, а не в рамках того что существует абстрактный исполнитель, который конкретную конструкцию воспринимает не так как другой.
V>Фишка в том, что оба этих исполнителя на уровне машины Тьюринга будут эквивалентны.
Допустим V>Поэтому т.з. на абстрактного "исполнителя" вообще не важна.
Никак не вытекает. "Поэтому" тут нет.
S>>Ты имеешь в виду что select отсортирует таблицу по-месту, изменив тем самым содержимое таблицы? Если нет, то в чем здесь императив?
V>В алгоритме в терминах инструкций, очевидно: V>- найди таблицу V>- выбери проекцию V>- отсортируй результат
Где изменение состояния?
V>И откуда ты решил, что по-месту?
Я предположил что присутстсвует побочный эффект. Если он присутствует, то где бы ему еще быть? Может в "найди таблицу"?
DG>>>а может в декларативной: дай в отсортированном виде значения поля name из таблицы users.
V>Хороший пример, показывающий эквивалентность декларативного определения и определения в терминах инструкций.
Так которая из инструкций императивна?
V>На самом деле, на любом выбранном уровне подробностей эти определения будут эквивалентны. Они будут неэквивалентны лишь тогда, когда попытаемся приписать для любого выбранного примера разный уровень подробностей декларативному и императивному.
На самом деле императивность селекта не показана пока.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Внутри результирующей последовательности OrderBy может менять что угодно. Внутри исходной — нет. S>>Между делом, у тебя опять что-то с определениями. Определение чистой функции не допускает побочные эффекты. Т.е. чистая функция не может обладать побочными эффектами по определению. У тебя же она и чистая с одной стороны, и с побочным эффектом с другой.
V>Ну да, например ленивость... Самый что ни на есть побочный эффект, "выпрямляющий" вычисления.
Ленивость (грамотно выполненная) не является побочным эффектом. Грамотно выполненная — это значит что нет никакого способа узнать, были ли выполнены вычисления или нет. Ленивый список в хаскеле — хороший пример. Lazy<T> в дотнете — плохой, т.к. у него есть свойство, по которому можно определить факт вычисления. Возьми, пожалуйста какой-нибудь хороший пример и продемонстрируй побочный эффект от ленивости.
V>Тут уже как-то обсуждалось похожая тема. Кароч, с понятием "побочный эффект" надо быть аккуратней, бо речь всегда может идти только о доступном для осязания/измерения/использования побочном эффекте, иначе можно считать что его нет.
Речь именно о доступных для осязания побочных эффектах. См. определение. Если осязаемого нет — считай что его нет. Например, грамотная ленивость.
V>Именно так эмулируется ФП императивном вычислительном базисе, через допущения относительно видимости побочных эффектов.
Я не понял, о чем речь.
DG>>>и соответственно, не смотря на то, что функция чисто функциональная по определению — результат выражения зависит от истории применения orderby-ев к последовательности S>>А разве кто-то утверждал что результат применения чистых по определению функций не должен зависить от последовательности их применения?
V>А это уже заворот на 10-й круг в этом обсуждении. Можно смело завязывать, стороны выдохлись.
А чем закончились 9 кругов в конкретно этом аспекте? Таки не должен зависеть?
S>Ну т.е. как в случае с существованием переменной (понятия ЯВУ) ты ищешь переменную в исполняющемся коде, так и декларативность языка ты определяешь не по конструкциям языка, а по вычислителю?
По вычислительной модели. Это принципиально. См. для сравнения движки языков программирования в ограничениях: ты задаешь цель ("что"), и они ее находят ("как" — перебором или векторным спуском, но нас это не касается). И да, любой современный высокоуровневый язык предоставляет ср-ва деклараций НАД обязательно подразумеваемой вычислительной моделью. Для того, чтобы признать кусок кода без побочных эффектов декларативным в сравнении с императивным, порождающим идентичную программу, это надо совсем уж тщательно выбрать обсуждаемый уровень и точку зрения на него, бо с т.з. вычислительного базиса обе программы одинаково декларативны.
S>Ну что мне сказать? Скажу что я не разделяю такую позицию.
Вижу, и некоторые другие не разделяют. Причем, именно последние буквально несколько лет... когда ФП стало популярным, хотя ему столько же, сколько Лиспу.
ИМХО, с некоей непонятной мне легкостью стали пытаться обзывать традиционно рассматриваемый ранее уровень "как" уровнем "что". Т.е. зачем-то для ФП некоторые предпочитают ОПУСКАТЬСЯ в рассмотрении происходящего на один уровень, на уровень неких подробностей алгоритма, называя эти подробности уровнем "что" для низлежащей ф-ой модели исполнения. Ничего более смешного не видел, т.к. этот трюк требует слишком много допущений и натяжек... и к тому же, фактически не имеет аргументов против, когда аналогичное начинаешь совершать с императивным программированием. Бо нет в реальной программе никакого "мира" (как ты приводил пример), а есть вполне конечное мн-во состояний. И высокоуровневая императивная программа — несомненно декларативное описание автомата над этим состоянием. Так же, как и идентичная функциональная. Речь идет лишь об инструменте описания, но оба рассматриваемых инструмента равномощны по-определению, коль позволяют порождать идентичные программы с т.з. низлежащей вычислительной модели. Вглядись в происходящее: не может быть описание алгоритма в стиле control flow быть более декларативным, чем блок-схема алгоритма, бо оба описывают один и тот же граф вычислений с очень близким уровнем подробностей. Единственно что, в некоторых местах control flow не задает явно порядок вычисления, дык уже звучал аргумент, что тот же С++ тоже не задает явно порядок вычисления аргументов ф-ий, т.е. однозначно интерпретируемый исходный код, не содержащий UB, будет обладать теми же характеристиками, что аналогичный ф-ий код, для которого не важен порядок вычисления аргументов. Понимаешь что происходит? Вот эту миниатюрную с т.з. низлежащей вычислительной модели разницу в уровнях описания (возможное местами абстрагирование от порядка исполнения веток... но лишь местами) пытаются выдать за водораздел м/у декларативным и недекларативным. Это искажение самого термина "декларация".
V>>Во избежание спекуляций, без контекста и рассмотрения подробностей отвечать на это не буду. Бо я именно согласен или обсуждать вглубь, или никак вообще. Любой Тьюринг-полный язык императивен по своему определению, например Хаскель. S>По какому определению, позволь? не по этому? S>
S>В теории вычислимости исполнитель (множество вычисляющих элементов) называется тьюринг-полным, если на нём можно реализовать любую вычислимую функцию.
Гы, поднимись в определениях на один уровень раньше и посмотри, что есть вычислимая ф-ия.
Своими словами — это та, для которой существует конечная программа в терминах пошаговых инструкций над идеальной машиной (с бесконечной памятью).
S>Раскрой, пожалуйста, как из такой полноты вытекает императивность?
Из той, что два ф-ых преобразователя с памятью (напр. машины Тьюринга), выдающие одинаковую выходную последовательность в ответ на одинаковую входную, считаются эквивалентными, и так же существует взаимное однозначное преобразование таких автоматов.
Еще не ощутил всю иронию происходящего?
Уровень "что" для любой полноценной программы, пусть даже на функциональном языке, т.е. любое ТЗ для нее — это описание поведения эквивалентного автомата. Вот прямо отсюда можно начинать сворачивать все обсуждения относительно попыток приписать уровень "что" любым другим уровням, кроме относительных ТЗ в иерархии программных единиц... потому что иной подход потребует неких натяжек и обязательного условия не рассматривать ничего уровнем выше и ни дай бог ничего уровнем ниже. А я на это пойти не могу. Вернее могу, но только в обсуждении других вычислительных моделей, ведь есть же еще модели, помимо машины Тьюринга и тоже с разными интересными св-вами.
V>>То, что в нем есть ФВП, ленивость и иммутабельность — это лишь приятные плюшки, но не более. Неимперативным в принципе может быть только Тьюринг-неполный язык и никакой другой. S>Пруф? Или хотя бы направление рассуждений доказательства? Пока ты не доказал что хаскель императивен, я считаю его существование опровержением твоего тезиса.
Пруф по ссылке выше, а так же курить эквивалентность автоматов. И на всякий случай (заранее) можно покурить эквивалентность структурных автоматов и абстрактных, но можно поверить и на слово.
S>>>В том что программа на Хаскеле описывает результат. А императивная программа описывает последовательность действий.
V>>Нет, это тебя опять несет на высоту птичьего полета. Программа на Хаскеле для IO всегда описывает именно действия, которые будет совершать эта ф-ия. То, что любая ф-ия на самом деле возвращает ф-ию — это св-во ленивости, а не чистой ф-сти. Тут ты пытаешься всё свалить в кучу. Я видел твою "расшифровку" монады IO, но даже этого не требуется, коль IO ф-ия ленива. S>Ленивость не означает императивность, не так ли?
Ленивость — это изолированный мини-автомат, это та самая классическая ф-ия с памятью, которая и зовется автоматом. Именно ленивость позволяет Хаскелю упорядочить последовательность вычислений, делая их детерминированными, т.е. это именно инструмент детерминированной реализации программы по вышестоящему императивному ТЗ. Т.е. таки ленивость не то, что означает императивность, она именно для возможности привнесения императивности и существует, см поведение I-комбинатора в ленивой среде. Это такой комбинатор, для которого можно установить необходимый и достаточный порядок вычисления аргументов вместо произвольного. Теперь срослось, где именно идет переход из потенциально "параллельного" в "последовательное"? Фишка ленивости в том, что позволяет безболезненно переносить наработки лямбда-исчисления для использования в программу, где требуется детерминированная последовательность операций. В общем, иначе было бы гораздо сложнее реализовать исходное императивное ТЗ на чистом ФП, если бы не ленивость. Пришлось бы бороться с комбинаторным взрывом при вычислении (в общем случае рекурсивном) всех аргументов всех операций. И не факт, что программа имела бы останов...
Здравствуйте, samius, Вы писали:
V>>Ну да, например ленивость... Самый что ни на есть побочный эффект, "выпрямляющий" вычисления. S>Ленивость (грамотно выполненная) не является побочным эффектом. Грамотно выполненная — это значит что нет никакого способа узнать, были ли выполнены вычисления или нет. Ленивый список в хаскеле — хороший пример. Lazy<T> в дотнете — плохой, т.к. у него есть свойство, по которому можно определить факт вычисления. Возьми, пожалуйста какой-нибудь хороший пример и продемонстрируй побочный эффект от ленивости.
Зачем же от ленивости-то? Я сейчас с удовольствием почитал собственный аргумент, но в твоей озвучке. Итак... если нет возможности ощутить как-либо побочный эффект, он есть, или его нет?
V>>Тут уже как-то обсуждалось похожая тема. Кароч, с понятием "побочный эффект" надо быть аккуратней, бо речь всегда может идти только о доступном для осязания/измерения/использования побочном эффекте, иначе можно считать что его нет. S>Речь именно о доступных для осязания побочных эффектах. См. определение. Если осязаемого нет — считай что его нет. Например, грамотная ленивость.
V>>Именно так эмулируется ФП императивном вычислительном базисе, через допущения относительно видимости побочных эффектов. S>Я не понял, о чем речь.
Ну т.е. побочные эффекты таковы, что необнаруживаемы ср-вами языка программирования. Но они есть, бо язык тьюринг-полный.
DG>>>>и соответственно, не смотря на то, что функция чисто функциональная по определению — результат выражения зависит от истории применения orderby-ев к последовательности S>>>А разве кто-то утверждал что результат применения чистых по определению функций не должен зависить от последовательности их применения?
V>>А это уже заворот на 10-й круг в этом обсуждении. Можно смело завязывать, стороны выдохлись. S>А чем закончились 9 кругов в конкретно этом аспекте? Таки не должен зависеть?
Не закончились, судя по всему.
Просто уже раз 10 говорилось, что порядок выполнения ф-ий можно задать явно, прямо как список инструкций в императивном программировании. А твой "мир" протаскивать как монаду State, например. Получишь выражение одного базиса через другой с идентичным уровнем подробностей. ЧТД. Т.е. никакой базис ни над каким сверху не стоит в отношении "что"->"как", если брать выражение одного через другой. Фундаментально здесь то, что вот это вычисление вложенных ф-ий происходит не одномоментно, а упорядочено, т.е. начинает быть наблюдаемым точно такой же фактор времени, смены стадий вычислений, можно оперировать понятием "контекст вычисления" (см замыкания), что суть мгновенный снимок текущего состояния вычислителя и прочее и прочее. Там всей разницы, что в чистом ФП мы получаем копию вычислителя, а в императивном — оперируем тем же самым. Но! При таких строго последовательных вычислениях (например, без лямбд и продолжений, как в императивном программировании) у нас будет оставаться только копия вычислителя, а оригинал будет все время выкидываться... Вопрос на засыпку: как определить достоверно, что мы выкинули, копию или оригинал? А нельзя ли выкидывать сразу копию?
Здравствуйте, samius, Вы писали:
DG>>а разговоры о терминах — это всегда деструктивный разговор, не создающий нового знания. S>Деструктивный разговор — это употребление общеизвестных терминов в недоступном для собеседника смысле. Я просто не пойму о чем ты разговариваешь. Слова знакомы, а суть противоречит тому что я знаю. Какого разговора ты хочешь без согласования терминов? О чем? Ты будешь говорить о своем, а я недоумевать, как такое возможно, думая о совершенно другом? S>Если хочешь, что бы тебя понимали, нужно договориться с терминами.
Ну вообще, похоже ты давно понял, что речь идет о детерминированности. Однако я соглашусь с твоим оппонентом, что таки побочные эффекты зачастую нарушают детерминированность. Собственно, только в этом нарушении их и обвиняют, никаких других грехов им пока не приписывали. С другой стороны с этим "побочным эффектом" побочного эффекта (о как) успешно борются через локальность вычислений.
Здравствуйте, Sinclair, Вы писали:
V>>Для состояния твоей программы — несомненно одинаковы. Я ведь не зря привел пример ввода-вывода в ф-х языках. S>А с каких это пор stdout перестал быть состоянием моей программы? S>Вот я бы, скажем, отказался принимать у вас программу с перепутанным порядком вывода в консоль — она нарушает ТЗ.
Угу, кто тебя спросит. Если несколько процессов или потоков от независимых либ делят одну консоль, то там получается занятная каша в любом случае, бо нам состояние консоли недоступно и мы даже не в состоянии организовать "атомарный" доступ к ней.
V>>Дык, тело сишной printf тоже не имеет никаких побочных эффектов, является полностью реентерабельной. Если бы были побочные эффекты именно внутри кода printf, она не была бы реентерабельной и многопоточной. S> Совершенно необязательно. Вы опять делаете неявные предположения, которые очевидно неверны. Попробуйте формально доказать, что наличие побочных эффектов запрещает функции быть реентерабельной и многопоточной.
Ну это легко, если договориться о том, что есть "запрещает". Давай считать, что это означает потерю детерминированности для эквивалентного конечного автомата. Если некий другой поток меняет состояние автомата в моменты работы ф-ии, то результат ее недетерминирован. Если ф-ия при повторном вхождении затирает предыдущее состояние собственного незавершенного вызова, то результат предыдущего вызова будет недетерминирован.
V>>Вооот... мы дошли до цепочек вычислений в ф-ом программировании, через механизм вложенных вызовов ф-ий, мне даже не пришлось 10-й раз намекать, как для случая РА. Чем не императив? ИМХО, только точкой зрения на происходящее. S>Тем, что в императиве все вычисления зависимые, если нам не удаётся доказать обратное (что в общем случае крайне трудно). А в декларативном программировании у нас есть только те зависимости, которые мы описали явно.
Я исхожу и того, что доказать на уровне компилятора не так-то сложно. Ведь работает как-то же линковщик, ресолвя абсолютно все до одной зависимости.
V>>Это ес-но, речь шла о том, где заканчивается декларативное и начинается императивное. Твои побочные эффекты могут быть нам недоступны, т.е. не влиять на элементы нашей программы, примерно как в монаде IO. В чем тогда отличие якобы декларативного Хаскеля в случае этой монады, и императивной программы, которая использует только "чистые" ф-ии и процедуры, не изменяющие неявно состояния нашей программы? S>Императивная программа в любом случае опирается на состояние некоторого "вычислителя". Скажем, в дотнете и яве вся семантика описана в терминах виртуальной машины и последовательности её состояний.
Функциональная тоже опирается на некий контекст, который разный в разных точках вычисления.
V>>Первое предложение ты написал поторопимшись. У нас уже есть низлежащая аппаратура, которая близка по принципу работы машине Тьюринга, поэтому последовательность инструкций мы имеем как вычислительный базис. Отличие ф-ых языков от императивных в том, что ф-ые скрывают от программиста внутреннюю работу с состоянием, т.е. на уровне пользовательской программы побочных эффектов НЕТ. Я же привел printf не случайно, показав точно такой же случай, что на уровне пользовательской программы нет никаких побочных эффектов. S>Что такое "уровень пользовательской программы"?
Доступный тебе из твоей программы из используемого языка.
S>>>В частности, можно вычислить первые N чисел Фибоначчи не за N^2, а за N, несмотря на явно рекурсивное определение этой функции.
V>>Это св-во ленивости, а не ф-сти. Точно такой же эффект достижим и в императиве аж бегом, если навертишь свой некий тип Lazy<T>. Не смущает, что сам механизм ленивости основан на запоминании состояния в точке вычисления? S>Это не свойство ленивости. Это возможность выполнять преобразования программы, опираясь на гарантии соответствия. Тот самый Lazy<T> применим только там, где порядок вычислений неважен. Если используемые в вычислении функции пользуются побочными эффектами, применение Lazy<> приведёт к нарушениям логики.
Сам Lazy<T> — это один сплошной побочный эффект. Всё преобразование заключается в запоминании состояния в точке вычисления.
V>>Дык, если ширина каждого слоя узлов ровно 1, то порядок будет ровно 1. Я же не зря этот пример привел, подводя к нужной мысли... но ты и сам его показал на примере цепочки printf. S>Ну как можно быть таким невнимательным? В примере с printf ширина каждого слоя узлов, очевидно, 2.
Один из них, Console, все время передается выше как результат предыдущей операции.
S>И ваша мысль, к которой вы так тонко подводили, малоинтересна: да, есть такой частный случай, когда выражение представлено в виде последовательности унарных операций. Вот в нём декларативная программа однозначно сведётся к императивной. Увы, в природе такие случаи встречаются исчезающе редко.
Нет, я имел ввиду показанный тобой случай.
S>Да пожалуйста. Мне эта тема вообще неинтересна. Вы упорно отказываетесь понимать одну простую вещь: вся могучесть РА как раз в том, что она насквозь декларативна, и позволяет выполнять широкий класс оптимизаций.
Она декларативна, угу, но лишь по отношению к уровню, который будет ее реализовывать. Это ты зашел на очередной круг.
V>>Ага, вот где путаница, только не у меня. Для случая join мы имеем те же N, а не M (по крайней мере одна из сторон соединения просматривается целиком для любого из join). S>У вас.
V>>Я словесно имел ввиду, что полная формула в пределе такая: V>>K1 * O(N * log N) + K2 * O(N), где K2 обычно гораздо гораздо хуже K1. S>1. И куда у вас делась кардинальность второго отношения? У нас отношения с кардинальностями N и M. При этом M итерируется полностью, а среди N мы выполняем поиск. S>2. Ну и где же обещанные O(N*M)? Внезапно оказалось, что никаких умножений в стоимости join уже нет.
Это от того, что ты рассматриваешь лишь один join из 6-ти возможных, постоянно скипая зачем-то мой ответ тебе на один и тот же вопрос. Похоже на какое-то юление.
V>>Очередной бред. При чем тут "пессимистика" и логические чтения? S>При том, что логические чтения превращаются в физические с вероятностью, отличной от 1.
Пофиг, ляпнуть про "пессимистику", приводя оценки в терминах "O" — это можно выкидывать всё обсуждение. Я уже не знаю, что же я с тобой обсуждал-то... и где ты имел ввиду асимптотику оценки, а где ее приближение. Каша, в общем.
S>Реальный запрос никогде не будет выполнять больше физических чтений, чем логических.
Вот это открытие... А как же так получилось?
S>Поэтому если я вижу оценку в 8000 логических чтений, это не означает, что время выполнения запроса будет равно 8000 поделить на IOPS моего диска.
Реальный IOPS, слава богу, от тебя мало зависит. Иначе бы у тебя было максимум 70 обработанных экстентов в секунду, а их, однако, многие тысячи. Спасибо кешу операционки.
S>Cache Hit Ratio может быть достаточно высоким для того, чтобы сократить эту оценку на порядок.
V>>обычно бывает ровно наоборот, зависимости для малого кол-ва данных обычно гораздо похуже, чем для асимптотики сверху. Ты этого не знаешь, поэтому порешь ерунду насчет "пессимистичности"... Ровно наоборот, оценка сверху зачастую — самая оптимистичная, т.к. для нее отбрасываются незначащие компоненты для бесконечно большого N. И эта оценка именно для логических чтений, независимо ни от какого cache hit ratio для твоих "больших размеров". Характерно, что для малого кол-ва данных тоже может случиться низкий cache hit ratio, например, если каждая страница в некоей выборке будет нужна лишь однажды, и не случится к ней того самого повторного обращения... S>Я рекомендую прекратить делать предположения о том, чего я знаю, а чего нет.
Почему нет, если ты сам это написал? Да и вообще... Твои посты состоят из этих манер чуть менее чем полностью. Характерно, что я еще не видел таких двух коллег, у которых полностью совпадал бы багаж знаний и опыта. Т.е. фактически любые два коллеги могут по разным вопросам отсылать друг друга нах или "пойти почитать", что в технических форумах эквивалентно.
V>>Оба предела асимптотики, выраженной в логических чтениях, что нижний, что верхний, никак не зависят от cache hit ratio. S>Правильно. Я говорю о переходе от логических чтений к физическим.
Угу... Сдается мне, что мои замечания в предыдущих постах просто не воспринимались...
V>>Ты сейчас подставляешься по самое нихочу, заканчивай умничать, где не ходил еще ни разу... S>Прекратите паясничать. Я вас уже столько раз ткнул носом в фактические идиотизмы, а вы по-прежнему пытаетесь понтоваться. Зачем?
Мой идиотизм — это в плане заблуждений относительно разметки страниц твоей любимой СУБД? Ты бы поосторожнее с такими вещами, бо они сами по себе тебя подставляют. Находясь на твоей стороне спора, я бы это вычислил в одну итерацию, что и делаю регулярно с твоими заблуждениями, а тебе потребовался примерно десяток.
V>>Есть асимптотика в логических чтениях — я с ней и не спорю. S>Более того, логические чтения можно рассчитать точно, а не в терминах асимптотики. И формулы будут практически такие, как мы с вами обсуждали.
В том то и дело, что не будут такие же. Там тупая формула по статистике, а вид операции для оценки уже не важен, бо весовая ф-ия не оперирует видами аналитик, она оперирует абсолютными значениями на выходе весовых ф-ий. Вся аналитика остается на этапе составления весовых ф-ий и больше ее не будет.
S>Забавно вы юлите. Ваши наблюдения про N*M для сложности join — тоже насчёт "вполне осязаемых соотношений"?
Ты дважды скипнул мои пояснения насчет джоин и теперь строишь мину при плохой игре. В предыдущем посте я на это уже отвечал.
V>>Фишка в том, что O(M*logN) не зависит от cache hit ratio даже для физических чтений, бо O — это ограничение асимптотики сверху. Но оценок может быть много, не обязательно оценка сверху. Ты же сам давал ссылку на что-то там по оценке сложности (хоть я и не ходил по ним, бо теорию, в отличии от, знаю неплохо, а оценка сложностей конкретных алгоритмов не интересует пока не столкнусь с ними). S>Теорию вы, простите, знаете на три с минусом. Если вы стоимость join прикидываете на глаз с такими ошибками, то игнорировать шанс почитать учебники не стоит.
Мде? А мне показалось, что ты из всех операций join подразумеваешь только одну. И на основе этого хочешь поставить мне тройку.
Хороший бы вышел из тебя преподаватель, нечего сказать. Был у нас такой один, требовал чтобы отвечали как он давал иначе сразу трояк. А если дашь более общий вид формулы — вообще выгнать может.
V>>Наблюдения — это объективная реальность. S>Зато их интерпретация у вас не лучше, чем в анекдоте про Василия Ивановича, Петьку, и таракана.
Таки в том посте я давал не интерпретацию, а именно что наблюдения. Относительно ширины данных и их кол-ва.
S>И где в моих рекомендациях было сказано, что кластерный индекс будет неэффективен для относительно небольших данных? S>ваше активное сопротивление.
Из твоих рекомендаций этого не видно вообще. Просто дело в том, очевидно, что слишком много всяких эффектов влияют на производительность. К тому же, хорошо известно, что не всякий алгоритм лучший в терминах O на бесконечно большом объеме данных даст лучшие показатели на малых объемах. Тут уже нужна оценка снизу. А оценка снизу обычно на многие порядки сложнее асимптотики предела сверху.
V>>Да ладно тебе, своими "идите почитайте" ты нарываешься везде и всюду, где бы я не встречал твои посты. Заслужено получаешь в ответ. А здесь опять попытался сумничать не по теме обсуждения. S>Так что ж я могу сделать, если вы не идёте и не читаете?
Делиться информацией очевидно, чтобы все ходы были записаны...
V>>Я вижу крайне узкоспециализированный опыт и весьма оригинальные эффекты из-за этого, см начало обсуждение. Например о ненужности реляционной модели, и о прочих вредительских советах. S>Где вы нашли "о ненужности реляционной модели"? Процитируйте. V>>Так всегда бывает, когда сложную и объемную область изучают на примере конкретного продукта, непонимая, где и откуда растут ноги, и почему именно так. S>Удивительное дело. У меня вот как раз полностью обратное впечатление. S>Скажем, идея о том, что кластерный индекс требует фиксированного размера записи сама по себе может появиться только от непонимания, откуда растут ноги, и почему именно так.
Скажем так, я видел много разных кластерных индексов до MS SQL, и прекрасно понимал, в чем их цимус.
S>У меня такой идеи никогда даже не появлялось. Наверное, это оттого, что я плохо понимаю дизайн СУБД и причины, по которым принимаются те или иные решения в них. К сожалению, суровая практика показала, что мои некомпетентные идеи ближе к истине, чем ваши.
В обсуждении конкретной СУБД? Возможно... В принципе, учитывая заложенную дороговизну операций ввода-вывода в MS SQL действительно, возможно будет эффективней использовать неэффективную структуру данных с лишним уровнем индирекции.
V>>Дать тебе ссылку на устройство связанного списка? S>Ну, как только я перестану его понимать, или скажу глупость типа "стоимость вставки в связный список — это O(N)" — сразу давайте ссылку.
Ну так согласно доке, сервер старается поддерживать равномерное заполнение кластерного индекса. Т.е. мало выделить +1 страницу, надо еще данные в ближайших таблицах распихать. Если ты не прочитал целиком в том месте, самое время вернуться и освежить.
V>>Еще раз, как именно происходит преобразование структурных формул SQL к вариантам планов запросов, которые ЗАТЕМ оцениваются оценочной ф-ей. S>1. Выполняется парсинг запроса в AST S>2. Выполняется преобразование AST в дерево логического плана исполнения запроса (про то, как применяется паттерн Visitor, надо рассказывать?)
Да, если можно. Хотя не надо, мне надоели бесконечные итерации, лучше я расскажу, чтобы не растягивать. Вот прямо здесь ты пропустил важный пункт — это выпрямление кванторов общности и кванторов существования в исходном запросе. В этом и заключается построение логического плана запроса. MS SQL тормозит в сравнении с файловыми базами далеко не всегда. Он сливает им только на простых операциях, типа выборки из одной, максимум двух таблиц по натуральному join. Зато когда идут вложенные кванторы, да еще с разными перекрестными зависимостями/ограничениями на разных уровнях... то на движке JET приходится по десятку раз переформулировать один и тот же запрос, крутя его граф во все стороны, чтобы получить приемлемую эффективность, а MS SQL стабильно дает почти один и тот же план запроса, невзирая на формулировку. Ему даже join писать не надо, пиши таблицы через запятую, он сам разберет, а JET в этом месте просто уйдет в глубокий своп. Так вот, логических планов запросов тоже несколько, после выпрямления всех кванторов, т.е. после сведения их ко всяким пересечениям, произведениям и ограничениям. Итого, идет как минимум два уровня перебора вариантов. А далее можно как в классике, например как в теории игр использовать оценочный аппарат с отсечением — ничего нового. Я потому и отбрасываю конкретный вид оценочной ф-ии, что она не принципиальна в после установления к какому классу сложности относится конкретное вычисление и какой аппарат использовать. Вряд ли ошибусь, если предположу использование такого раздела нечеткой логики как теория приближенных вычислений (бо статистика почти всегда врет, если не только что пересчитали, т.е. стоит задача выдавать решение в этих условиях).
S>3. Начинается построение физического плана запроса: S>3.1. Порождаются различные версии физического плана. Они похожи на выражения РА, вот только в аргументах у них немножко другие объекты, чем отношения, и операции немножко другие, чем в РА
А вот тут уже и есть та самая скука. Механика.
S>3.1.1. В частности, в отличие от РА, для аргументов очень важен порядок сортировки кортежей — от него зависит применимость операций
Это атрибут физической модели и прямиком может топать как параметр в некую ф-ю оценки. РА здесь не при чем. По конкретной таблице есть требуемая операция в терминах РА — выборка / проекция / ограничение. Никаких других операций над конкретной таблицей НЕТ. (переименование оставлю за бортом). Теперь эти операции требуется расписать в индексах, при том что зависимостями исходной таблицы и индексов СУБД полностью владеет. Вот тебе тот самый второй уровень вложенности итерации перебора планов запросов.
S>3.1.2. В отличие от РА, для операций важны применяемые алгоритмы — это влияет не только на оценку стоимости, но и на отсортированность результата
Это опять ты оперируешь атрибутами физической модели. Атрибут для каждой конкретной структуры является константой, а для оценочной ф-ии — параметром.
S>3.2. Процесс порождения не пытается построить все возможные планы. Это бы привело к слишком большим затратам на оптимизацию. Применяются как эвристические методы отсечения, так и основанные на оценках стоимости планов. S>3.3. Как только оптимизатор найдёт приемлемый физический план выполнения (по оценкам), он передаёт план на исполнение.
Для решений на основе векторного спуска или отсечений в задачах оптимизации — как только пройдет экстремум. Для простых случаев экстремум находится через обычное решение задачи (матрицы) линейного программирования, ХЗ используется ли это в MS SQL.
S>Вы, пытаясь доказать свои заблуждения, выделяете фазу генерации вариантов планов запросов в отдельный этап. Ок, даже если бы это было так, всё равно РА было бы недостаточно.
Таки итерация планов запросов — это несомненно самый сложный и затратный этап. По этой теме, очевидно, тебя можно пинать с самых первых постов. Неужели query rewriting является таким уж незначащим шагом? Да именно здесь запросы из стоимости в часы превращаются в запросы стоимостью доли секунд... Процедура затратная, однако, бо перебор по большому итоговому дереву обычно... Построение AST в сравнении с этим этапом не видно и под микроскопом, и это подтверждают файловые базы, не располагающие оптимизаторами — они начинают выдавать данные фактически мгновенно. Немудрено, SQL крайне прост в парсинге, и сложность его выражений обычно смехотворна с т.з. формальных грамматик.
S>Я вам с самого начала говорил — то, что там применяется, только похоже на РА. Основы, несомненно, те же. S>Однако, используются расширения РА, что вы упорно отказываетесь признать. Если bookmark lookup и можно заменить на операцию join, если добавить к таблице и к индексу "невидимый" атрибут RID, то для операции sort никакого аналога в РА найти не удастся.
А почему бы не пройтись предварительно по предложенным Коддом расширениям? Чтобы составить представление, чем же именно и куда расширяют? Расширения-то предлагались и они есть де-факто, только совсем с другой стороны, не на этом уровне. Предлагались расширения как ср-во описания более высокоуровневых операций и далее итеративно. Короче, абсолютно все предлагаемые расширения по-определению являлись "синтаксическим сахаром" и были выразимы в базисе.
Тебе не нужен никакой sort на уровне PA, тебе нужно только обозначить вид соединения, а уже низлежащий слой пусть примет решение, исходя из прогноза по данным — будет он строить индекс, или и так пойдет. Я вижу, что включение в план запроса, наглядности ради, подробностей операций, просто сбивает тебя с толку. Понимаешь, породить sort из задачи join — не нужен вообще никакой специальный мат-аппарат, просто некое пороговое значение кол-ва элементов из оценки статистики, и решение да/нет — строим индекс или не строим. В сравнении с перебором вариантов плоского представления кванторов — это полное тьфу. Если сервер умудряется составлять на десятки вариантов формулировок одного и того же запроса один и тот же план — то он перебирает никак не меньше десятка вариантов, правильно? А я бы предположил цифру еще на порядок менее скромную.
V>>Действительно, при переборе планов запросов некоторые ветки перебора могут отсекаться довольно рано, но это было бы известно тебе и так, если бы ты понимал, как именно эти планы строятся по выражениям SQL. И да, в твоей ссылке такой информации нет. S>Это потому, что вы проигнорировали ссылку на Гарсиа-Молина.
Если ты про ту, где отметился Ульман в соавторстве — то это не самая лучшая ссылка. И таки принято автором считать Ульмана, а остальную братию в соавторстве. И таки хотелось бы узнать, на что именно ты там пытался сослаться? На какой раздел?
S>Угу. Вот только в реляционной модели зависимости — это некоторые факты, которые можно вычислить. А не свойства отношений, хранимые в некоторой форме.
Если ты опять и снова имеешь ввиду атрибуты физической модели, то они всегда представлены набором неких констант для целей оценки. Остальное — точно такие же зависимости, как классической реляционной модели.
V>>Давай прежде посмотрим, как работает memory mapped file, а потом будем делать выводы. S>Куда именно вы предлагаете посмотреть?
На принципы виртуального ввода-вывода для популярной архитектуры. Memory-mapped файл — это фактически "родная" технология ввода-вывода для аппаратуры.
V>>Не все-равно в затратах копирования данных во внутренний кеш операционки. S>Вы опять ту же песню на новый лад. Ок, давайте сравним затраты времени на копирование 64кб данных в памяти и запись 64кб на диск. S>Как вы думаете, каково будет соотношение Thdd/Tram?
Если в затратах проца, то в первом случае когдаздо экономнее, чем во втором. Операции с файловой системой тривиальны алгоритмически, остальное делается само через DMA. К тому же, прокачка через DMA не портит кеш процессора, в отличие от операций копирования, да и на современном рейде суммарная буферная емкость даже в винчестерах уже ощутима. В общем, перелопачивать "вручную" данные весьма накладно. Ты так и не понял замечание про 1 всего измененный байт.
V>>К тому же, в случае memory mapped file мы даем операционной системе решать, как ей лучше сбрасывать данные, а лучше драйвера ввода-вывода все-равно никто не знает. S>Ну, если, конечно, нас не интересует целостность данных — то да, таки драйвер ввода-вывода рулит. S>У MS Access всю жизнь была, скажем так, весьма примитивная recovery model. Поэтому можно, наверное, было некоторые решения отдать на откуп драйверу ввода-вывода.
Тем не менее, если низлежащая файловая система транзакционна, то можно было бы это учесть... тем более, в рамках одной конторы. Оракл не постеснялся специально под себя разработать файловую систему, а глядя на MS SQL такое ощущение, что правая рука не знает что делает левая в MS.
V>>В принципе, там суть не в IOPS, разумеется, а в том, что сервер, в отличие от ОС, знает, когда у него конец транзакции, поэтому использует копии страниц кеша, а не пользует память кеша страниц ОС напрямую, как в случае memory mapped file. Твои экстенты — они сугубо для уменьшения кол-ва дорогостоящих операций ввода/вывода, чтобы копировать за раз больше страниц... Но не на диск, разумеется, бо это не серверу решать (вот почему Oracle давно уже разраобтал свою файловую систему, чтобы держать всё под конторлем), а для того лишь, чтобы уменьшить кол-во системных вызовов, каждый из которых относительно дорогой (даже холостой вызов этого последовательного АПИ ввода-вывода стоит единицы микросекунд). S>О да. Действительно. Единицы микросекунд мы экономим там, где сам вызов стоит миллисекунды. Кто бы мог подумать.
Смотря что происходит в эти миллисекунды. Если поток ожидает или вызов асинхронный — это одно, а если активно работает — совсем другое. Для многозадачной ОС и СУБД сверху — разница большая. К тому же,
про буферы рейдов уже напоминал. Как раз размеров буферов сейчас хватает, чтобы сектор диска к головке подъехал, но IO при этом не ждал завершения операции.
S>"Мои екстенты" были, естественно, применены для оптимизации алгоритма поиска свободных страниц при размещении. Ну и для того, чтобы повысить шансы на последовательное чтение — мы это уже обсуждали.
Там вся оптимизация заключается в уменьшении кол-ва операций ввода-вывода, а ничего другого, кроме как укрупнять блоки, тут не придумаешь. А у этого подхода есть обратная сторона в избыточности копирований тем большей, чем крупнее блоки.
V>>И кстати, IOPS на SSD-массивах скоро будет уже под миллионы и выше, при том, что пропускная способность DMA ограничена, так что тебе стоит пересмотреть свои представления. V>>http://www.ixbt.com/news/hard/index.shtml?15/38/75 S>Ок, интересные новости. Это, несомненно, повлияет на дизайн СУБД в ближайшие лет 10. Тем не менее, общие соображения останутся прежними. И мои представления легко пересмотреть — потому что они хорошо структурированы Я заменю в них маленький кусочек, и всё будет в порядке. А вот вам придётся ставить заново все эксперименты — или выбросить накопленный опыт на помойку.
Ес-но, будут заново все эксперименты. Так и только так и никак иначе.
Плевать на маленькие кусочки чьих либо представлений о чем либо... я уже воробей стреляный, на романтику не ведусь. Мы порой такие эффекты в плане производительности современных процов наблюдаем, что оперирование толко лишь асимптотикой вызывает у меня легкую иронию. Бо многократное проседание эффективности при той одной и той же асимптотике можно получить тупо из-за неаккуратного обращения с кешем процессора. Чем больше ядер на кристалле, тем зависимей картинка от сценариев обращения с внутренним кешем.
V>>Основная фишка memory-mapped file в том, что в этом случае мы имеем меньше слоев IO, чем при последовательном способе, т.е. банально меньше копируется данных м/у дисковым кешем операционной системы и нашими буферами (страницами). Я уверен, что в MS SQL будет пересмотрен способ работы со страницами в ближайших версиях, бо сейчас их способ уже малость архаика. S>Можно подумать, memory mapped files были придуманы недавно.
— Не было столько памяти, сколько сейчас;
— не было таких технологий оптимизации ввода-вывода на уровне операционки, в условиях большей доступной памяти, как сейчас;
— ввод-вывод был узким звеном, а сейчас некоторые рейды способны выдавать и принимать быстрее, чем поспевают обрабатывать топовые процессоры.
Для сравнения, если раньше даже на более слабом проце при компиляции С++ у меня редко было более 50% загрузки проца, бо он "отдыхал" на ввод-выводе, то сейчас при куда как более мощном многоядерном проце у него заметно выше загрузка! Более 75% стабильно, а это уже ого разница.
Ну и экономия таблиц маппинга повышает эффективность: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366720(v=vs.85).aspx согласно принципа работы виртуальной памяти.
А с эффективностью сейчас малость траблы. Все устойчиво имеют некое проседание эффективности после перекомпиляции на x64.
V>>Пффф, по кругу... Тебе осталось показать, что запись результата мощности O(N*M) будет дешевле сортировки одной из компонент. S>Ну откуда же у нас взялось N*M в результате, если мы выполняем join по равенству атрибута?
А как же остальные виды join?
(нравится мне эта ненавязчивая тема )
V>>В рантайм warning-ов не бывает, зато бывают исключения. А компиляторы? — все популярные. S>Вас не затруднит привести опции компилятора, которые заставляют его выбрасывать исключения при целом переполнении для gcc и msvc?
Для GCC лучше поясню, а то из доки с непривычки будет непонятно:
-ftrapv
-fnon-call-exceptions
Два этих параметра надо одновременно. Без второго первый не выбросит исключение.
V>>А если по-делу: предпросмотром на этом сайте кто-нить займется или теперь уже никогда? S>Вы зачем это у меня спрашиваете?
Дык, RSDN-тим или как? Я бы и сам подправил давно уже, там дел на несколько минут.
Просто раздражает читать собственные очепятки...
S>Совершенно верно. Зачем же вы продолжаете спорить? Одной рукой вы признаёте наличие двух (и более) моделей; одновременно с этим другой рукой упорно отрицаете наличие границы между ними. Получается, даже простейшие вещи на современных ЯП нельзя писать, основываясь на предположениях школьной арифметики относительно поведения целых чисел.
Я не отрицаю границ. Я говорю о том, что кол-во связей различных разделов IT очень велико. Повторное использование знаний тоже крайне велико, и это объективная реальность. Что я пальцы оловом обжигал в студенчестве — примочку гитарную проектировал, что потом чисто-программный джиттер-буффер многоконтурный отлаживал в VoIP — занимался одним и тем же из САУ. Все эти осциллографы и умение зачистить контакт с одной стороны и знание конкретного ЯП с другой — шелуха это всё... инструментарий и не более того. А в плане границ ПО и железа всё еще печальнее. Одних только способов реализации конечных автоматов я знаю около десятка, каждый из который все дальше от железа и все ближе к микропрограммам и потом к обычному ПО. Четкой границы нет вообще. По крайней мере в своем стаже я как раз по всему градиенту тщательно прошелся. Одна и та же модель абсолютно на любом уровне. Автомат он и в Африке автомат, что на регистрах, что в ООП-парадигме.
Кароч, примеров-то можно привести много... Но суть одна, если взять все знания из области IT, то ты получишь граф из довольно счетного кол-ва узлов, но огромного кол-ва связей м/у ними. Увидеть "четкую границу" можно лишь при невладении целыми кластерами таких узлов... в этом месте будет космический вакуум и несколько световых лет до следующего знакомого кластера узлов. Даже по обсуждаемому вопросу: пройдись по теории сложности, теории игр, линейному программированию, АИ, нечеткой логике и т.д. Потом попробуй "четко отделить" задачу оптимизации плана запросов от этих разделов. С удовольствием запасусь попкорном и понаблюдаю за этими попытками.
Это конечно без перехода на личности, но, чесслово, "монолитностью" своей утомил. Помимо явного упрощенчества это просто уже какие-то определенные черты характера.
Я хорошо тебя выслушал уже с первого раза и твоё мнение понял. Имеешь демократическое право на собственное мнение, никто его не оспаривает. Но на 10-й раз давно пора было отправить по известному адресу.
S>Это примерно соответствует вашей позиции про то, что "нужно изучать нижележащую платформу", несмотря на то, что вы думаете, что я с этим несогласен. S>А на самом деле я несогласен с тем, чтобы склеивать в одну кучу модель школьной арифметики и модель чисел ограниченной разрядности.
Ммм... да вроде поразрядную арифметику как раз в школе и изучают, если склероз не изменяет, где-то в 1-м классе... Оно уже в куче by design.
Вернее, никакой кучи нет, есть обычный поразрядный счет и надо лишь помнить, что кол-во разрядов не бесконечно.
S>Ошибки случаются оттого, что свойства одной модели слепо переносятся на другую модель. Ну, примерно как оценки свойств ISAM-модели переносятся на модель кластерных индексов.
Кластерный индекс — он и в африке кластерный. Для меня явилось лишь неожиданностью нефиксированный размер строки. Это минимум вдвое проседание выборки из страницы из-за +1 к косвенности.
S>Из-за этого возникают предположения типа "вставка в кластерный индекс требует O(N) записей на диск", и принимаются неверные архитектурные решения.
Именно так? А можно цитату целиком?
S>И вот тут ключ к успеху — понимать, какие свойства относятся к чему. К примеру, "использование более одного индекса с низкой селективностью при поиске в одной таблице дороже, чем сочетание index seek с bookmark lookup и filter" как правило работает в случае хеш-индексов и btree-индексов. А вот для случая bitmap-индексов это полностью неверно.
А еще можно не плодить битмап-индексы и таки не бояться явной избыточности, зато организовать себе кластерный индекс по нужному полю/полям. Избыточность не запрещена даже в реляционной модели, бояться тут нечего. Все-равно, ориентироваться надо лишь на результаты замеров в конкретных сценариях и ни на что более.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Ну т.е. как в случае с существованием переменной (понятия ЯВУ) ты ищешь переменную в исполняющемся коде, так и декларативность языка ты определяешь не по конструкциям языка, а по вычислителю?
V>По вычислительной модели. Это принципиально. См. для сравнения движки языков программирования в ограничениях: ты задаешь цель ("что"), и они ее находят ("как" — перебором или векторным спуском, но нас это не касается).
Движки языков программирования в ограничениях не могут быть выполнены на МТ? Или они тоже императивны по твоей логике?
V>И да, любой современный высокоуровневый язык предоставляет ср-ва деклараций НАД обязательно подразумеваемой вычислительной моделью. Для того, чтобы признать кусок кода без побочных эффектов декларативным в сравнении с императивным, порождающим идентичную программу, это надо совсем уж тщательно выбрать обсуждаемый уровень и точку зрения на него, бо с т.з. вычислительного базиса обе программы одинаково декларативны.
С точки зрения вычислимости на МТ ничто не декларативно. Вообще не пойму, что ты тут обсуждаешь с такой позицией?
S>>Ну что мне сказать? Скажу что я не разделяю такую позицию.
V>Вижу, и некоторые другие не разделяют. Причем, именно последние буквально несколько лет... когда ФП стало популярным, хотя ему столько же, сколько Лиспу. V>ИМХО, с некоей непонятной мне легкостью стали пытаться обзывать традиционно рассматриваемый ранее уровень "как" уровнем "что". Т.е. зачем-то для ФП некоторые предпочитают ОПУСКАТЬСЯ в рассмотрении происходящего на один уровень, на уровень неких подробностей алгоритма, называя эти подробности уровнем "что" для низлежащей ф-ой модели исполнения. Ничего более смешного не видел, т.к. этот трюк требует слишком много допущений и натяжек...
Не видел ничего более смешного чем судить о декларативности по вычислительной модели и возможности выполнить ее на МТ.
V>и к тому же, фактически не имеет аргументов против, когда аналогичное начинаешь совершать с императивным программированием. Бо нет в реальной программе никакого "мира" (как ты приводил пример), а есть вполне конечное мн-во состояний. И высокоуровневая императивная программа — несомненно декларативное описание автомата над этим состоянием. Так же, как и идентичная функциональная. Речь идет лишь об инструменте описания, но оба рассматриваемых инструмента равномощны по-определению, коль позволяют порождать идентичные программы с т.з. низлежащей вычислительной модели. Вглядись в происходящее: не может быть описание алгоритма в стиле control flow быть более декларативным, чем блок-схема алгоритма, бо оба описывают один и тот же граф вычислений с очень близким уровнем подробностей. Единственно что, в некоторых местах control flow не задает явно порядок вычисления, дык уже звучал аргумент, что тот же С++ тоже не задает явно порядок вычисления аргументов ф-ий, т.е. однозначно интерпретируемый исходный код, не содержащий UB, будет обладать теми же характеристиками, что аналогичный ф-ий код, для которого не важен порядок вычисления аргументов. Понимаешь что происходит? Вот эту миниатюрную с т.з. низлежащей вычислительной модели разницу в уровнях описания (возможное местами абстрагирование от порядка исполнения веток... но лишь местами) пытаются выдать за водораздел м/у декларативным и недекларативным. Это искажение самого термина "декларация".
Давай вообще начнем с того, откуда в определении декларативности программы взялась вычислительная модель?
V>>>Любой Тьюринг-полный язык императивен по своему определению, например Хаскель. S>>По какому определению, позволь? не по этому? S>>
S>>В теории вычислимости исполнитель (множество вычисляющих элементов) называется тьюринг-полным, если на нём можно реализовать любую вычислимую функцию.
V>Гы, поднимись в определениях на один уровень раньше и посмотри, что есть вычислимая ф-ия. V>Своими словами — это та, для которой существует конечная программа в терминах пошаговых инструкций над идеальной машиной (с бесконечной памятью).
У меня нет слов. Ты из возможности вычислить в МТ делаешь вывод о императивности! Хорошо, покажи мне декларативную по-твоему функцию, такую, что для нее не существует программы МТ.
Вернемся к императивности по Тьюринг-полноте. Если (допустим, хоть это и не так) любой Т-полный язык императивен, то может быть существуют не Т-полные языки(программирования), которые невычислимы на МТ и которые все-таки декларативны?
S>>Раскрой, пожалуйста, как из такой полноты вытекает императивность?
V>Из той, что два ф-ых преобразователя с памятью (напр. машины Тьюринга), выдающие одинаковую выходную последовательность в ответ на одинаковую входную, считаются эквивалентными, и так же существует взаимное однозначное преобразование таких автоматов.
Покажи, пожалуйста, связь с определением императивности.
V>Еще не ощутил всю иронию происходящего? V>Уровень "что" для любой полноценной программы, пусть даже на функциональном языке, т.е. любое ТЗ для нее — это описание поведения эквивалентного автомата. Вот прямо отсюда можно начинать сворачивать все обсуждения относительно попыток приписать уровень "что" любым другим уровням, кроме относительных ТЗ в иерархии программных единиц... потому что иной подход потребует неких натяжек и обязательного условия не рассматривать ничего уровнем выше и ни дай бог ничего уровнем ниже. А я на это пойти не могу.
Ирония лишь в том, что между определением декларативности и описанием поведения эквивалентного автомата связи нет.
V>Вернее могу, но только в обсуждении других вычислительных моделей, ведь есть же еще модели, помимо машины Тьюринга и тоже с разными интересными св-вами.
Я верю, что можешь. Из других вычислительных моделей ты наверняка сделаешь другие не менее интересные выводы, чем императивность всего, вычислимого на МТ.
V>>>То, что в нем есть ФВП, ленивость и иммутабельность — это лишь приятные плюшки, но не более. Неимперативным в принципе может быть только Тьюринг-неполный язык и никакой другой. S>>Пруф? Или хотя бы направление рассуждений доказательства? Пока ты не доказал что хаскель императивен, я считаю его существование опровержением твоего тезиса.
V>Пруф по ссылке выше, а так же курить эквивалентность автоматов. И на всякий случай (заранее) можно покурить эквивалентность структурных автоматов и абстрактных, но можно поверить и на слово.
Ты сначала докажи причастность автоматов к определению императивности.
Вообще не понятно, как ты трактуешь Тьюринг-полноту. Походу у тебя Т-неполным языком является язык, который нельзя выразить в МТ
V>>>Нет, это тебя опять несет на высоту птичьего полета. Программа на Хаскеле для IO всегда описывает именно действия, которые будет совершать эта ф-ия. То, что любая ф-ия на самом деле возвращает ф-ию — это св-во ленивости, а не чистой ф-сти. Тут ты пытаешься всё свалить в кучу. Я видел твою "расшифровку" монады IO, но даже этого не требуется, коль IO ф-ия ленива. S>>Ленивость не означает императивность, не так ли?
V>Ленивость — это изолированный мини-автомат, это та самая классическая ф-ия с памятью, которая и зовется автоматом. Именно ленивость позволяет Хаскелю упорядочить последовательность вычислений, делая их детерминированными, т.е. это именно инструмент детерминированной реализации программы по вышестоящему императивному ТЗ. Т.е. таки ленивость не то, что означает императивность, она именно для возможности привнесения императивности и существует, см поведение I-комбинатора в ленивой среде. Это такой комбинатор, для которого можно установить необходимый и достаточный порядок вычисления аргументов вместо произвольного. Теперь срослось, где именно идет переход из потенциально "параллельного" в "последовательное"? Фишка ленивости в том, что позволяет безболезненно переносить наработки лямбда-исчисления для использования в программу, где требуется детерминированная последовательность операций. В общем, иначе было бы гораздо сложнее реализовать исходное императивное ТЗ на чистом ФП, если бы не ленивость. Пришлось бы бороться с комбинаторным взрывом при вычислении (в общем случае рекурсивном) всех аргументов всех операций. И не факт, что программа имела бы останов...
Очень много буков. Но следствие императивности из ленивости не раскрыто. Хотя, ты мог бы применить свой любимый довод — вычислимость на МТ (следствие императивности из которого не доказано).
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Ну да, например ленивость... Самый что ни на есть побочный эффект, "выпрямляющий" вычисления. S>>Ленивость (грамотно выполненная) не является побочным эффектом. Грамотно выполненная — это значит что нет никакого способа узнать, были ли выполнены вычисления или нет. Ленивый список в хаскеле — хороший пример. Lazy<T> в дотнете — плохой, т.к. у него есть свойство, по которому можно определить факт вычисления. Возьми, пожалуйста какой-нибудь хороший пример и продемонстрируй побочный эффект от ленивости.
V>Зачем же от ленивости-то? Я сейчас с удовольствием почитал собственный аргумент, но в твоей озвучке. Итак... если нет возможности ощутить как-либо побочный эффект, он есть, или его нет?
Смотри определение
V>>>Именно так эмулируется ФП императивном вычислительном базисе, через допущения относительно видимости побочных эффектов. S>>Я не понял, о чем речь.
V>Ну т.е. побочные эффекты таковы, что необнаруживаемы ср-вами языка программирования. Но они есть, бо язык тьюринг-полный.
Да, Т-полнота для тебя означает вычислимость на МТ, это я уже понял. Хотя по определению Т-полноты это возможность реализовать любую функцию, вычислимую на МТ.
Продемонстрируй все-таки побочный эффект от вычисления функции, описанной на хаскеле. Только без бэкдоров типа unsafePerformIO.
S>>>>А разве кто-то утверждал что результат применения чистых по определению функций не должен зависить от последовательности их применения?
V>>>А это уже заворот на 10-й круг в этом обсуждении. Можно смело завязывать, стороны выдохлись. S>>А чем закончились 9 кругов в конкретно этом аспекте? Таки не должен зависеть?
V>Не закончились, судя по всему.
V>Просто уже раз 10 говорилось, что порядок выполнения ф-ий можно задать явно, прямо как список инструкций в императивном программировании. А твой "мир" протаскивать как монаду State, например. Получишь выражение одного базиса через другой с идентичным уровнем подробностей. ЧТД. Т.е. никакой базис ни над каким сверху не стоит в отношении "что"->"как", если брать выражение одного через другой. Фундаментально здесь то, что вот это вычисление вложенных ф-ий происходит не одномоментно, а упорядочено, т.е. начинает быть наблюдаемым точно такой же фактор времени, смены стадий вычислений, можно оперировать понятием "контекст вычисления" (см замыкания), что суть мгновенный снимок текущего состояния вычислителя и прочее и прочее. Там всей разницы, что в чистом ФП мы получаем копию вычислителя, а в императивном — оперируем тем же самым. Но! При таких строго последовательных вычислениях (например, без лямбд и продолжений, как в императивном программировании) у нас будет оставаться только копия вычислителя, а оригинал будет все время выкидываться... Вопрос на засыпку: как определить достоверно, что мы выкинули, копию или оригинал? А нельзя ли выкидывать сразу копию?
Тебя увело куда-то в сторону. Еще раз. Должен ли результат применения чистых по определению функций зависеть от последовательности их применения?
Теперь по поводу, нельзя ли выкидывать сразу копию... Копию выкидывать сразу можно при определенных условиях. Но это трюк вычислителя, а не языка программирования. Из того что копия может быть выкинута вычислителем, не следует ровно ничего в отношении императивности языка, описывающего порождение копии.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
DG>>>а разговоры о терминах — это всегда деструктивный разговор, не создающий нового знания. S>>Деструктивный разговор — это употребление общеизвестных терминов в недоступном для собеседника смысле. Я просто не пойму о чем ты разговариваешь. Слова знакомы, а суть противоречит тому что я знаю. Какого разговора ты хочешь без согласования терминов? О чем? Ты будешь говорить о своем, а я недоумевать, как такое возможно, думая о совершенно другом? S>>Если хочешь, что бы тебя понимали, нужно договориться с терминами.
V>Ну вообще, похоже ты давно понял, что речь идет о детерминированности.
Нет, до сих пор не понял. V>Однако я соглашусь с твоим оппонентом, что таки побочные эффекты зачастую нарушают детерминированность.
Зачастую — это не серьезно. Могут нарушать, а могут и не нарушать. V>Собственно, только в этом нарушении их и обвиняют, никаких других грехов им пока не приписывали. С другой стороны с этим "побочным эффектом" побочного эффекта (о как) успешно борются через локальность вычислений.
локальный побочный эффект не является побочным эффектом извне функции.
Вообще речь была об OrderBy и о том что нестабильность может сделать его нечистым. Я отвечал что что бы сделать его нечистым, или точнее недетерминированным, нужна не просто нестабильность, а нестабильность со случайным выбором порядка элементов с равным ключем.
Я могу согласиться с тем что OrderBy детерминирован лишь условно, с точностью не включая Object.ReferenceEquals, и возможность влиять на поведение результирующего перечислителя через исходную последовательность. Но если мы уж назвали OrderBy чистым, значит мы закрыли глаза на эти косяки.
Но причем же тут побочный эффект? Где побочный эффект у OrderBy? Где то, что соответствует определению побочного эффекта в OrderBy? Без согласования терминов ответить однозначно невозможно. Ведь DarkGray называет побочным эффектом просто отсутствие стабильности сортировки.
Здравствуйте, vdimas, Вы писали:
V>Угу, кто тебя спросит. Если несколько процессов или потоков от независимых либ делят одну консоль, то там получается занятная каша в любом случае, бо нам состояние консоли недоступно и мы даже не в состоянии организовать "атомарный" доступ к ней.
Вам — это кому? Вас занесло не в ту степь. По-вашему, выходит, что писать осмысленные программы на С вовсе нельзя — ведь даже положиться на то, что консоль выводит данные в определённом порядке невозможно. Однако, практика показывает, что программы такого рода вполне себе пишутся, и каким-то волшебным образом функция printf выводит данные в stdout строго в одном, нужном нам порядке. Каким же волшебным образом это происходит, не подскажете?
V>Ну это легко, если договориться о том, что есть "запрещает". Давай считать, что это означает потерю детерминированности для эквивалентного конечного автомата.
Какого конечного автомата? V>Если некий другой поток меняет состояние автомата в моменты работы ф-ии, то результат ее недетерминирован. Если ф-ия при повторном вхождении затирает предыдущее состояние собственного незавершенного вызова, то результат предыдущего вызова будет недетерминирован.
Как интересно. Давайте тогда уж условимся о том, что считать результатом функции. То, что она возвращает через return, или состояние некоего "вычислителя", разделяемого между всеми функциями? Если первое, то, конечно же, функция, хоть как-то работающая с разделяемым состоянием у нас сразу потеряет детерминистичность. Даже если у неё нет никаких побочных эффектов.
А если второе — то нам вопросы детерминированности результата отдельной функции становятся, в общем-то, малоинтересны. Вместо них мы введём понятие сериализуемости, через которое определим корректность. И сразу же окажется, что функции с побочными эффектами станут совершенно спокойно реентерабельны и потокобезопасны.
V>Я исхожу и того, что доказать на уровне компилятора не так-то сложно. Ведь работает как-то же линковщик, ресолвя абсолютно все до одной зависимости.
Линковщик резолвит не те зависимости.
V>Функциональная тоже опирается на некий контекст, который разный в разных точках вычисления.
Этот "контекст" в ФП не имеет никакого отношения к состоянию вычислителя. Это всего лишь правила связывания аргументов.
V>Доступный тебе из твоей программы из используемого языка.
Из программы на C доступно довольно много всего про состояние императивного вычислителя.
V>Сам Lazy<T> — это один сплошной побочный эффект. Всё преобразование заключается в запоминании состояния в точке вычисления.
Поэтому он императивен. Дальше что?
V>Один из них, Console, все время передается выше как результат предыдущей операции.
И тем не менее, порядок вычисления "вторых" узлов неважен, если вычисления не имеют побочных эффектов.
V>Нет, я имел ввиду показанный тобой случай.
Значит, вы чего-то не понимаете.
V>Она декларативна, угу, но лишь по отношению к уровню, который будет ее реализовывать. Это ты зашел на очередной круг.
Нет.
V>Это от того, что ты рассматриваешь лишь один join из 6-ти возможных, постоянно скипая зачем-то мой ответ тебе на один и тот же вопрос. Похоже на какое-то юление.
Это вы юлите. Вы мне тут только что утверждали, что equi-join будет стоить O(N*M) для случая, когда объём данных много больше объёма ОП, и ни один из результатов не отсортирован. Я вам показал что нет, ничего подобного. Теперь вы опять пишете мне, что имели в виду join по произвольному выражению (тогда причём тут сортировка?), а когда я напишу вам, что это — редкий случай, вы опять станете передергивать и делать вид, что речь идёт о соотношении объёма данных и памяти. Так что ли?
Ок, тогда давайте вернёмся к тому, с чего всё начиналось. Вы мне утверждали, что
если некая соединительная операция из 3-х (грубо) составляющий выполняется в 4 раза быстрее, что каждая в среднем стала выполняться быстрее в корень 3-й степени из 4.
Вы какие именно соединительные операции здесь имели в виду? Неужели в вашем проекте все соединения были по произвольной функции, и размер результата был примерно равен кросс-продукту? Как же вы тогда ускорили их путём применения индексов?
V>Вот это открытие... А как же так получилось?
Очень просто: логические чтения считают все обращения к кэшу страниц. Если происходит cache miss, то приходится реально выполнить физическое чтение.
V>Реальный IOPS, слава богу, от тебя мало зависит. Иначе бы у тебя было максимум 70 обработанных экстентов в секунду, а их, однако, многие тысячи. Спасибо кешу операционки.
Вы опять возвращаетесь к предположению о том, что СУБД пользуется кэшем операционки. Это далеко не всегда так — я вам об этом уже писал. Приличные СУБД не полагаются на тупой кэш операционки и отключают его, чтобы не мешал. Для выяснения этого факта даже исходники читать не надо.
V>Мой идиотизм — это в плане заблуждений относительно разметки страниц твоей любимой СУБД? Ты бы поосторожнее с такими вещами, бо они сами по себе тебя подставляют.
Вам полный список привести? Пожалуйста, мне нетрудно:
1.
фиксированные размеры страниц нужны исключительно для нужд кластерных индексов, которые принципиально живут только в контексте детерминированных размеров
Нет, кластерным индексам детерминированность размера данных совершенно неважна
2.
Кластерный индекс хорош лишь там, где seek по всем данным в процессе двоичного поиска относительно дешев. Т.е. когда размеры таблицы заведомо меньше размера ОП
Нет, кластерные индексы прекрасно работают и там, где размеры таблицы много больше размера ОП.
3.
линейка от 6-ки до MS SQL 2000 была в своё время изучена настолько подробно, насколько это вообще возможно, включая местами исходники.
Это вы просто соврали — потом, правда, поправились, что изо всей линейки читали исходники только 6го сервера. Хотя видно, что насчёт "насколько это вообще возможно" — мягко говоря, преувеличение.
4.
Если для некластерного у меня получалось получалось 1-2 страницы, для не самой большой таблицы, то для случае этого же индекса как кластерного — легко десяток-полтора сканированных страниц ради одного значения.
Вот ещё одно вранье. Сканирование полутора десятков страниц для одного значения, даже в случае самой широкой таблицы, требует примерно 10 в 36 степени записей. Мне лень считать, о каких объёмах собственно данных тут может идти речь.
5.
Для случая вставки в кластерный индекс всегда трудоемкость минимум O(n), помимо операции обновления дерева индекса
Нет, стоимость вставки в кластерный индекс без учёта стоимости обновления дерева — O(1), с учётом — O(log N).
6. Рассуждения о стоимости Join-ов — можете посмотреть выше.
Эти ошибки смотрелись бы нормально, если бы не подавались с таким апломбом и предположениями, что я вообще базы данных видел только на картинке, а вы якобы рассмотрели всё вплоть до исходников.
V> Находясь на твоей стороне спора, я бы это вычислил в одну итерацию, что и делаю регулярно с твоими заблуждениями, а тебе потребовался примерно десяток.
Чтобы находиться на моей стороне спора, нужно разбираться в вещах, о которых идёт спор
V>В том то и дело, что не будут такие же. Там тупая формула по статистике, а вид операции для оценки уже не важен, бо весовая ф-ия не оперирует видами аналитик, она оперирует абсолютными значениями на выходе весовых ф-ий. Вся аналитика остается на этапе составления весовых ф-ий и больше ее не будет.
Ок, напишите эту тупую формулу.
V>Мде? А мне показалось, что ты из всех операций join подразумеваешь только одну. И на основе этого хочешь поставить мне тройку.
Вы хотите и про другие виды join поговорить? Давайте сначала разберёмся с самым простым случаем. Потом можно будет перейти к остальным, если у вас ещё останется желание со мной поспорить.
V>Хороший бы вышел из тебя преподаватель, нечего сказать. Был у нас такой один, требовал чтобы отвечали как он давал иначе сразу трояк. А если дашь более общий вид формулы — вообще выгнать может.
Ну, если формула неверна, то правильно сделает.
V>Таки в том посте я давал не интерпретацию, а именно что наблюдения. Относительно ширины данных и их кол-ва.
А предположение о фиксированности размера записей откуда взялось? Из dBase III?
V>Из твоих рекомендаций этого не видно вообще. Просто дело в том, очевидно, что слишком много всяких эффектов влияют на производительность. К тому же, хорошо известно, что не всякий алгоритм лучший в терминах O на бесконечно большом объеме данных даст лучшие показатели на малых объемах. Тут уже нужна оценка снизу. А оценка снизу обычно на многие порядки сложнее асимптотики предела сверху.
Ок, то есть вы хотите перейти обратно к примеру, когда данных мало и они целиком влезают в ОП? Ну давайте поговорим об этом.
V>Скажем так, я видел много разных кластерных индексов до MS SQL, и прекрасно понимал, в чем их цимус.
Я не знаю, что вы имеете в виду под словом "цимус", но судя по вашим репликам в этой ветке вы всё-таки смешали особенности конкретной реализации кластерных индексов с общим понятием "кластерный индекс". Отсюда смешные предположения про их характеристики в MS SQL.
V>Ну так согласно доке, сервер старается поддерживать равномерное заполнение кластерного индекса. Т.е. мало выделить +1 страницу, надо еще данные в ближайших таблицах распихать. Если ты не прочитал целиком в том месте, самое время вернуться и освежить.
Боюсь, что вернуться и освежить придётся именно вам.
1. Сервер не старается поддерживать равномерное заполнение кластерного индекса. Это было бы глупо.
2. Что вы называете "распихать"? Никакого распихивания не происходит — просто страница сплитится на две. Половина данных попадает в одну, половина — в другую. Это позволяет снизить амортизированную стоимость вставки, т.к. последующие вставки в эти же страницы не будут приводить к сплиту.
V>Да, если можно. Хотя не надо, мне надоели бесконечные итерации, лучше я расскажу, чтобы не растягивать. Вот прямо здесь ты пропустил важный пункт — это выпрямление кванторов общности и кванторов существования в исходном запросе.
Это вы про замену Exists и All на join? Ну, это же не всё — такие же вещи происходят с in и вложенными запросами. V>В этом и заключается построение логического плана запроса.
V>MS SQL тормозит в сравнении с файловыми базами далеко не всегда. Он сливает им только на простых операциях, типа выборки из одной, максимум двух таблиц по натуральному join. Зато когда идут вложенные кванторы, да еще с разными перекрестными зависимостями/ограничениями на разных уровнях... то на движке JET приходится по десятку раз переформулировать один и тот же запрос, крутя его граф во все стороны, чтобы получить приемлемую эффективность, а MS SQL стабильно дает почти один и тот же план запроса, невзирая на формулировку. Ему даже join писать не надо, пиши таблицы через запятую, он сам разберет, а JET в этом месте просто уйдет в глубокий своп.
Верно.
V>Так вот, логических планов запросов тоже несколько, после выпрямления всех кванторов, т.е. после сведения их ко всяким пересечениям, произведениям и ограничениям.
И чем отличаются логические планы друг от друга?
Итого, идет как минимум два уровня перебора вариантов. А далее можно как в классике, например как в теории игр использовать оценочный аппарат с отсечением — ничего нового. Я потому и отбрасываю конкретный вид оценочной ф-ии, что она не принципиальна в после установления к какому классу сложности относится конкретное вычисление и какой аппарат использовать. Вряд ли ошибусь, если предположу использование такого раздела нечеткой логики как теория приближенных вычислений (бо статистика почти всегда врет, если не только что пересчитали, т.е. стоит задача выдавать решение в этих условиях).
S>>3. Начинается построение физического плана запроса: S>>3.1. Порождаются различные версии физического плана. Они похожи на выражения РА, вот только в аргументах у них немножко другие объекты, чем отношения, и операции немножко другие, чем в РА
V>Это атрибут физической модели и прямиком может топать как параметр в некую ф-ю оценки. РА здесь не при чем. По конкретной таблице есть требуемая операция в терминах РА — выборка / проекция / ограничение. Никаких других операций над конкретной таблицей НЕТ.
Куда делась сортировка?
S>>3.1.2. В отличие от РА, для операций важны применяемые алгоритмы — это влияет не только на оценку стоимости, но и на отсортированность результата V>Это опять ты оперируешь атрибутами физической модели. Атрибут для каждой конкретной структуры является константой, а для оценочной ф-ии — параметром.
Это не я, это сервер оперирует.
S>>Вы, пытаясь доказать свои заблуждения, выделяете фазу генерации вариантов планов запросов в отдельный этап. Ок, даже если бы это было так, всё равно РА было бы недостаточно.
V>Таки итерация планов запросов — это несомненно самый сложный и затратный этап.
Всё правильно. И уже на ней "просто РА" недостаточно. То, что вы продолжаете называть "атрибутами физической модели" является необходимым компонентом. Выбросьте эти атрибуты — и алгоритм перебора перестанет работать.
V>Тебе не нужен никакой sort на уровне PA, тебе нужно только обозначить вид соединения, а уже низлежащий слой пусть примет решение, исходя из прогноза по данным — будет он строить индекс, или и так пойдет.
Нет. Никакого "низлежащего слоя" нету — в физическом плане запроса указаны конкретные физические операции. Для их выбора нужно знать, что и как. Если в узле A мы выбрали merge join, то результат отсортирован по ключу, и в узле B, где мы джойним C с A, мы можем применять merge join или index nested loops join. И копать или нет дальше в эту сторону — принципиальный вопрос.
V>Я вижу, что включение в план запроса, наглядности ради, подробностей операций, просто сбивает тебя с толку. Понимаешь, породить sort из задачи join — не нужен вообще никакой специальный мат-аппарат, просто некое пороговое значение кол-ва элементов из оценки статистики, и решение да/нет — строим индекс или не строим.
Как интересно. То есть вы каким-то волшебным образом разделяете алгоритм построения физического плана на некоторые фрагменты, и произвольным образом называете одни из них "мат-аппаратом", а другие — нет? Это, несомненно, новое слово в построении запросов.
V>Если ты про ту, где отметился Ульман в соавторстве — то это не самая лучшая ссылка. И таки принято автором считать Ульмана, а остальную братию в соавторстве. И таки хотелось бы узнать, на что именно ты там пытался сослаться? На какой раздел?
На второй. Там, где про собственно реализацию.
V>Если ты опять и снова имеешь ввиду атрибуты физической модели, то они всегда представлены набором неких констант для целей оценки.
Да, я имею в виду "атрибуты физической модели". Благодаря которым оптимизатор знает, что индекс I1 по таблице T1 связан с этой таблицей. Именно благодаря этому оптимизатор вообще рассматривает варианты планов, включающие этот индекс, даже если вы ему явно об этом не сказали. А вот если вы построите свой "индекс" вручную — ну, например, как вы это называли "обыграете индекс при помощи отдельного отношения", оптимизатор не станет рассматривать его использование. Несмотря на наличие зависимостей, которые с точки зрения реляционной модели ничуть не хуже тех, что у "настоящего" индекса
S>>Как вы думаете, каково будет соотношение Thdd/Tram?
V>Если в затратах проца, то в первом случае когдаздо экономнее, чем во втором. Операции с файловой системой тривиальны алгоритмически, остальное делается само через DMA. К тому же, прокачка через DMA не портит кеш процессора, в отличие от операций копирования, да и на современном рейде суммарная буферная емкость даже в винчестерах уже ощутима. В общем, перелопачивать "вручную" данные весьма накладно. Ты так и не понял замечание про 1 всего измененный байт.
Я всё прекрасно понял. Напишите экспериментальную программу и мы легко убедимся, что я неправ.
V>Тем не менее, если низлежащая файловая система транзакционна, то можно было бы это учесть... тем более, в рамках одной конторы. Оракл не постеснялся специально под себя разработать файловую систему, а глядя на MS SQL такое ощущение, что правая рука не знает что делает левая в MS.
У MS была своя файловая система. Начиная с версии 7.0 они дропнули поддержку raw disks, потому что стоимость была высока, а выхлоп — никакой. Оракл просто многоплатформенный, у них не было возможности оптимизироваться под конкретную ФС (если не написать свою).
S>>"Мои екстенты" были, естественно, применены для оптимизации алгоритма поиска свободных страниц при размещении. Ну и для того, чтобы повысить шансы на последовательное чтение — мы это уже обсуждали.
V>Там вся оптимизация заключается в уменьшении кол-ва операций ввода-вывода, а ничего другого, кроме как укрупнять блоки, тут не придумаешь.
Если вы про оптимизацию выполнения запросов — кроме укрупнения блоков есть ещё много техник. Те же индексы разных видов. Тем более, что страница всё ещё 8к. V>А у этого подхода есть обратная сторона в избыточности копирований тем большей, чем крупнее блоки.
V>- Не было столько памяти, сколько сейчас; V>- не было таких технологий оптимизации ввода-вывода на уровне операционки, в условиях большей доступной памяти, как сейчас;
Это каких например? V>- ввод-вывод был узким звеном, а сейчас некоторые рейды способны выдавать и принимать быстрее, чем поспевают обрабатывать топовые процессоры.
Тем не менее в жизни мы наблюдаем отличны рост скорости процессоров и памяти, умеренный рост скорости линейного чтения с дисков, и очень слабый прогресс в IOPS. Только SSD несколько нарушают эту тенденцию. Однако вот, к примеру, команда Microsoft Exchange по-прежнему оптимизирует нагрузку на диск в терминах IO operations. То есть в ближайшие четыре года они не ожидают массового перехода на SSD.
V>Для сравнения, если раньше даже на более слабом проце при компиляции С++ у меня редко было более 50% загрузки проца, бо он "отдыхал" на ввод-выводе, то сейчас при куда как более мощном многоядерном проце у него заметно выше загрузка! Более 75% стабильно, а это уже ого разница.
Как интересно вы рассказываете. "Раньше" — это когда? Есть у меня подозрение, что просто с тех пор переписали компилятор, и он стал поддерживать многоядерность. Большинство старых компиляторов — однопоточные, так что на двухядернике больше 50% не получишь, даже если весь проект в кэше лежит.
V>Для MSVC V>http://msdn.microsoft.com/en-us/library/8wtf2dfz(VS.90).aspx
Осталось продемонстриовать, как эта опция поможет выкинуть исключение из вот такого кода:
int EpicFail(int a)
{
return a+1;
}
...
var a = EpicFail(MAX_INT);
V>Для GCC лучше поясню, а то из доки с непривычки будет непонятно: V>-ftrapv V>-fnon-call-exceptions V>Два этих параметра надо одновременно. Без второго первый не выбросит исключение.
Эти параметры помогут поймать багу в коде выше?
V>Дык, RSDN-тим или как? Я бы и сам подправил давно уже, там дел на несколько минут.
Я не занимаюсь веб-мордой. Те, кто занимается, эту ветку не читают. V>Я не отрицаю границ.
Ну и слава байту. Наконец-то договорились.
V>Кароч, примеров-то можно привести много... Но суть одна, если взять все знания из области IT, то ты получишь граф из довольно счетного кол-ва узлов, но огромного кол-ва связей м/у ними. Увидеть "четкую границу" можно лишь при невладении целыми кластерами таких узлов... в этом месте будет космический вакуум и несколько световых лет до следующего знакомого кластера узлов. Даже по обсуждаемому вопросу: пройдись по теории сложности, теории игр, линейному программированию, АИ, нечеткой логике и т.д. Потом попробуй "четко отделить" задачу оптимизации плана запросов от этих разделов. С удовольствием запасусь попкорном и понаблюдаю за этими попытками.
А чего тут пробовать? Нужно просто понимать, где в решениии что берётся откуда. И не путать божий дар с яичницей.
V>Ммм... да вроде поразрядную арифметику как раз в школе и изучают, если склероз не изменяет, где-то в 1-м классе... Оно уже в куче by design.
Нет. Первое упоминание чисел с ограниченной разрядностью в школе входило (в моё время) в учебник информатики за 11 класс. В первом-втором классах учат натуральным числам, которые могут быть бесконечной длины. И нигде в школе (кроме той же информатики мельком) не упоминается ничего похожего на целое переполнение. V>Кластерный индекс — он и в африке кластерный. Для меня явилось лишь неожиданностью нефиксированный размер строки. Это минимум вдвое проседание выборки из страницы из-за +1 к косвенности.
Если бы вы реально работали с настоящими базами данных, то вы бы знали, что CPU-cost на чтение данных из страницы пренебрежимо мал по сравнению со стоимостью дисковых операций.
S>>Из-за этого возникают предположения типа "вставка в кластерный индекс требует O(N) записей на диск", и принимаются неверные архитектурные решения. V>Именно так? А можно цитату целиком?
Я привёл выше. №5 в списке глупостей.
S>>И вот тут ключ к успеху — понимать, какие свойства относятся к чему. К примеру, "использование более одного индекса с низкой селективностью при поиске в одной таблице дороже, чем сочетание index seek с bookmark lookup и filter" как правило работает в случае хеш-индексов и btree-индексов. А вот для случая bitmap-индексов это полностью неверно.
V>А еще можно не плодить битмап-индексы и таки не бояться явной избыточности, зато организовать себе кластерный индекс по нужному полю/полям.
Можно. Но для принятия верного решения надо знать особенности конкретных архитектур, и не делать неверных предположений.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>>Но причем же тут побочный эффект? Где побочный эффект у OrderBy? Где то, что соответствует определению побочного эффекта в OrderBy? Без согласования терминов ответить однозначно невозможно.
DG>согласовывать необходимо сначала задачи, потом условия(границы) и только потом термины.
Ты пришел и сказал что OrderBy имеет побочный эффект. К чему, по какому поводу — осталось загадкой.
DG>можно долго согласовывать термин "маленький", но без задачи и условий — это будет не о чем. и тоже самое с большинством других терминов.
S>> Ведь DarkGray называет побочным эффектом просто отсутствие стабильности сортировки.
DG>из эквивалентности кода следует, что и проблемы эквиваленты.
Вот это опять к чему?
DG>mutable-программу можно один в один переписать в immutable (в чисто функциональный подход), когда каждая функция заменяется на такую же (но чистую), берущую весь мир и возвращающую весь мир. при этом побочный эффект из mutable-программы в один в один перейдет в побочный эффект функций в immutable-программе
Я не понимаю, к чему это, потому комментирую содержимое. Один в один — это вряд ли. Перейдет в побочный эффект чистой функции — тут ты опять забыл посмотреть определения побочного эффекта и чистой функции.
DG>побочный эффект появляется при решении задачи: DG> возможность вызывать только тот код, который необходим, DG>или другими словами: DG> возможность переставлять функции в коде, DG> заменять функцию на ее значение и т.д.
Побочный эффект появляется как средство достижения целей при решении совершенно разнообразных задач. Я все еще не понимаю смысл, который ты вкладываешь в побочный эффект.
DG>и соответственно утверждается, что побочным эффектом называется один из видов херотени, которая мешает выполнять эти операции
Утверждается что этот вид хрени называешь побочным эффектом только ты.
DG>возьмем код:
DG>можно ли здесь переставить местами или заменить на значение, хоть одну функцию? нет почему? сплошные побочные эффекты по определению
Да, в нем много побочных эффектов по определению.
DG>заменим на эквивалентный чисто функциональный код: DG>
DG>class C
DG>{
DG> public C(){this.X = new Random().Next();}
DG> public readonly int X;
DG> public readonly int Y;
DG>}
DG> ...
DG>void main()
DG>{
DG> C c = new C();
DG> ...
DG>}
DG>
Этот код не является чисто функциональным, т.к. использует недетерминированные функции.
Ты молоток, написал кучу кода. Но совершенно зря. Твои выводы ничего не стоят, т.к. используют термины, смысл которых очевидно искажен. Чистота — еще один термин, который ты толкуешь как-то по-своему.
S>Этот код не является чисто функциональным, т.к. использует недетерминированные функции.
Это ты про Random()? А разве нет его в ФП языках? В примере была демонстрация того, о чем мы тут говорим по всей ветке, забей ты на этот на Random, это уже просто придирки...
Дело в том, что современные компиляторы давно способны устанавливать все зависимости, именно это и позволяет им заниматься оптимизацией и спекулятивным выполнением. И я пока не видел ни разу, чтобы компилятор ф-ого языка оптимизировал лучше, чем компилятор императивного, невзирая на все рассуждения о потенциальной мощи оптимизируемости чистого кода. Это все наши суеверия, честно говоря. Компилятор способен оперировать зависимостями на многие порядки превосходящими по сложности наши возможности, поэтому аргументы из разряда "вот здесь заввисимости идут явно, а тут неявно" — просто нелепы для современных компиляторов. показанный код — это лишь малюсенький пример эквивалентных преобразований кода, которые давно способны выполнять современные компиляторы.
S>Ты молоток, написал кучу кода. Но совершенно зря. Твои выводы ничего не стоят, т.к. используют термины, смысл которых очевидно искажен. Чистота — еще один термин, который ты толкуешь как-то по-своему.
Дык более половины встреченных определений "чистоты" неполны. Многие из них вообще говорят о каких-то глобальных переменных, о вводе-выводе и прочий бред... А если у нас нет в языке глобальных переменных? В общем, более нелепого определения чистоты ф-ий, чем в Вики, я еще не видел, так что не мечи тут молнии.
Чистота — это отсутствие неявных зависимостей и ничего более. Зачем она вообще нужна? Детерминированности ради. Чистота ведь не самоцель ни разу, а лишь ср-во обеспечения детерминированности. Вернее, одно из ср-в, хотя и самое дешевое из всех. Дешевое в разработке, ес-но... бо в исполнении чистые программы пока ничего дешевого не показывают, скорее наоборот. ИМХО, самое дешевое ср-во обеспечения детерминированности на сегодня по всем показателям суммарно — это локальность состояний. Оно, к тому же, хорошо ложится на современные многоядерные архитектуры.
Здравствуйте, samius, Вы писали:
V>>Зачем же от ленивости-то? Я сейчас с удовольствием почитал собственный аргумент, но в твоей озвучке. Итак... если нет возможности ощутить как-либо побочный эффект, он есть, или его нет? S>Смотри определение
Не в Вики случайно?
V>>Ну т.е. побочные эффекты таковы, что необнаруживаемы ср-вами языка программирования. Но они есть, бо язык тьюринг-полный. S>Да, Т-полнота для тебя означает вычислимость на МТ, это я уже понял. Хотя по определению Т-полноты это возможность реализовать любую функцию, вычислимую на МТ. S>Продемонстрируй все-таки побочный эффект от вычисления функции, описанной на хаскеле. Только без бэкдоров типа unsafePerformIO.
Да запусти любую программу на хаскеле, да посмотри.
V>>Просто уже раз 10 говорилось, что порядок выполнения ф-ий можно задать явно, прямо как список инструкций в императивном программировании. А твой "мир" протаскивать как монаду State, например. Получишь выражение одного базиса через другой с идентичным уровнем подробностей. ЧТД. Т.е. никакой базис ни над каким сверху не стоит в отношении "что"->"как", если брать выражение одного через другой. Фундаментально здесь то, что вот это вычисление вложенных ф-ий происходит не одномоментно, а упорядочено, т.е. начинает быть наблюдаемым точно такой же фактор времени, смены стадий вычислений, можно оперировать понятием "контекст вычисления" (см замыкания), что суть мгновенный снимок текущего состояния вычислителя и прочее и прочее. Там всей разницы, что в чистом ФП мы получаем копию вычислителя, а в императивном — оперируем тем же самым. Но! При таких строго последовательных вычислениях (например, без лямбд и продолжений, как в императивном программировании) у нас будет оставаться только копия вычислителя, а оригинал будет все время выкидываться... Вопрос на засыпку: как определить достоверно, что мы выкинули, копию или оригинал? А нельзя ли выкидывать сразу копию? S>Тебя увело куда-то в сторону. Еще раз. Должен ли результат применения чистых по определению функций зависеть от последовательности их применения?
Коль речь о программе целиком, то бишь о композиции ф-ий — ес-но. Именно об этом и речь. Но ты зря скипнул рассуждения и вернулся на самое начало разговора, так мы будем топтаться на месте бесконечно. Уже пора было посмотреть на ООП и другие техники обеспечения локальности побочных эффектов.
Мои рассуждения в пред. посте применимы к технике ООП, ведь если объект не имеет зависимостей от глобальных данных, то любые вызовы его методов в однопоточном апартаменте сводятся к эквивалентным чистым, по тем рассуждениям что я привел. Потому что все зависимости явные, состояние объекта подается методам на исполнения явно.
S>Теперь по поводу, нельзя ли выкидывать сразу копию... Копию выкидывать сразу можно при определенных условиях. Но это трюк вычислителя, а не языка программирования. Из того что копия может быть выкинута вычислителем, не следует ровно ничего в отношении императивности языка, описывающего порождение копии.
Нет, из этого следует детерминированность, а только она и является целью, а вовсе не абстрактная "чистота".
DG>>деление на декларивный и императивный код появилось на заре становления программирования при решении задачи: может ли меняться код исполнения при той или иной записи программы? и в какой степени? S>Сам придумал? Если нет — дай ссылку.
это же ты не можешь и шагу ступить без одобрения от авторитета, ты и ищи.
чтобы эту задачу сделать за тебя — ты обязан для начала выдать полный список авторитетов, которых ты считаешь верными априори, а также привести правила по которым можно от утверждений текущего контекста перейти к утверждениям авторитета и обратно от утверждений авторитетов к текущей ситуации.
DG>>пока не было оптимизирующих компиляторов деление было более-менее четкое: DG>>пролог, sql — декларативные: исполнитель делает что хочет; S>Т.е. ты признаешь что sql когда-то был декларативным... Хорошо.
я признаю, что когда-то была достаточно точная граница, отделяющая одну группу языков от другой. и соответственно, в те времена можно было на одну группу языков вешать ярлык "декларативные", а на другую группу — "императивные", потому что на основе этих ярлыков можно было делать те или иные выводы.
сейчас же когда выражение на языке sql: select name from users; ничем не отличается от выражения на языке C#: db.users.Select(_ => _.name) — такой четкой границы нету, и соответственно — навешивание ярлыков "язык декларативный/язык императивный" ничего не дает, потому что на основе этих ярлыков никаких выводов сделать нельзя
S>Покажи мне способ строго задания sql запроса!
The NO_INDEX hint instructs the optimizer not to use one or more indexes for the specified table. For example:
SELECT /*+ NO_INDEX(employees emp_empid) */ employee_id
FROM employees
WHERE employee_id > 200;
Each parameter serves the same purpose as in "INDEX Hint" with the following modifications:
•If this hint specifies a single available index, then the optimizer does not consider a scan on this index. Other indexes not specified are still considered.
•If this hint specifies a list of available indexes, then the optimizer does not consider a scan on any of the specified indexes. Other indexes not specified in the list are still considered.
•If this hint specifies no indexes, then the optimizer does not consider a scan on any index on the table. This behavior is the same as a NO_INDEX hint that specifies a list of all available indexes for the table.
The NO_INDEX hint applies to function-based, B-tree, bitmap, cluster, or domain indexes. If a NO_INDEX hint and an index hint (INDEX, INDEX_ASC, INDEX_DESC, INDEX_COMBINE, or INDEX_FFS) both specify the same indexes, then the database ignores both the NO_INDEX hint and the index hint for the specified indexes and considers those indexes for use during execution of the statement.
http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements006.htm#SQLRF50411
S>А ты можешь назвать хоть один не императивный исполнитель sql? Хотя бы тот, который якобы был на заре становления программирования, когда sql еще был (по твоем рассуждениям) декларативен? Или тот, который (по рассуждениям vdimas-а) нельзя было бы выполнить на машине Тьюринга?
на заре становления sql-я, большую часть запросов sql мог выполнить только человек, в частности, например, из-за ограниченности кол-ва вложенных запросов и их видов в имеющихся программных исполнителях.
даже сейчас большинство main-stream баз имеют ограничения на сложность sql, которые они могут выполнять, при этом в самом sql-е таких ограничений нет.
DG>>при этом можно говорить, что такая запись более декларативная/менее императивная без явной фиксации исполнителя, если при этом измеряется какую степень свободы для исполнения дает та или иная запись; или если сравнивается мощность анализатора исполнителя, чтобы исполнитель мог получить ту или иную свободу исполнения, для той или иной записи кода. S>Напомни, каким образом исполнитель связан с определением декларативности, если ты в него заглядывал?
In computer science, declarative programming is a programming paradigm that expresses the logic of a computation without describing its control flow.[1] Many languages applying this style attempt to minimize or eliminate side effects by describing what the program should accomplish, rather than describing how to go about accomplishing it
в данном определении, о control flow чего? и о how для кого идет речь?
если ты ссылаешь на это определение и при этом требуешь четкости, то ты обязан сначала преобразовать это определение в четкую математическую форму и записать это определение через first-order logic и явное введение всех термов(понятий) в этом определении
V>>Гы, поднимись в определениях на один уровень раньше и посмотри, что есть вычислимая ф-ия. V>>Своими словами — это та, для которой существует конечная программа в терминах пошаговых инструкций над идеальной машиной (с бесконечной памятью). G>МТ эквивалента лямбда-исчислению, блок схемам и ЧРФ.
Если игнорить проблему останова, которая некритична для императивного вычислителя, например MT, коль программа работает во времени, генерируя при этом пользу. Но сия проблема мешает любой энергичной реализации ЧРФ из-за потенциально бесконечного зацикливания (см определение ЧРФ). А неэнергичная реализация обязательно императивна.
G>Так что можно считать вычислимой функцией ту, которую можно записать в виде ЧРФ. G>Вычислимость — свойство самой функции, императивность — свойство записи алгоритма вычисления.
М/у ними фундаментальная доказанная с разных сторон связь (см теоремы Геделя). Я ведь именно с этим и спорю, что приписать некое св-во одной системе и не приписать эквивалентной другой — банально неграмотно.
V>>Ленивость — это изолированный мини-автомат, это та самая классическая ф-ия с памятью, которая и зовется автоматом. Именно ленивость позволяет Хаскелю упорядочить последовательность вычислений, делая их детерминированными, т.е. это именно инструмент детерминированной реализации программы по вышестоящему императивному ТЗ. G>Прямо немерянное количество заблуждений в одном предложении. G>1) С чего это ТЗ императивно? Как раз хорошее ТЗ максимально декларативно. То есть не описывает конкретных шагов для получения результата.
Дык, ес-но ТЗ декларативно. См. моё определение декларативности. Просто оно в общем случае описывает эквивалентный автомат, например в терминах use-case... или различные виды описаний каких-нить протоколов и т.д. Ес-но описывается не устройство автомата, а его наблюдаемое поведение. Теперь см. определение декларативности, данное оппонентом. Или ты пока не разобрался, кто здесь с чем спорит?
G>2) С чего это ленивость- "автомат"? Может у них какие-то общие свойства есть?
С того, что ф-ий преобразователь с памятью — это и есть автомат, см определение автомата.
V>>Т.е. таки ленивость не то, что означает императивность, она именно для возможности привнесения императивности и существует G>Опять какой-то бессвязный набор слов.
Ну уж извини, кто на что учился...
G>Императивный алгоритм — тот который задает последовательность шагов, изменяющих некоторое состояние для достижения результата. Любой императивный алгоритм можно представить в виде структурированой блок-схемы.
Ну ок, первую лекцию по программирование за 1-е сентября 1-го курса ты усвоил... Молоток!
G>Ленивость заключается в том что агрументы функции вычисляются не при вызове, а при обращении. Это как раз дает непостоянную последовательность вычисления. То есть как раз в виде блок-схемы записать не получится.
Если не знаешь как — спроси. Этот императивный алгоритм над состоянием ленивого преобразователя выражается через две простейшие подпрограммы:
1. init
var func = init_func
var args = init_args
var result = unknown
2. call
if result is unknown then result = func(args)
Откровенная печаль, что опустились до этого уровня обсуждения... лучше посмотри со стороны... в другой раз отвечать на подобного качества посты я не найду времени, сорри.
V>>Это такой комбинатор, для которого можно установить необходимый и достаточный порядок вычисления аргументов вместо произвольного. G>То есть ленивость таки не соответствует фиксированному порядку, а значит не является императивным.
Таки комбинатору I приписывается достаточный порядок вычисления аргументов, с тем, чтобы не вычислять часть из них, если уже не требуется. Я бы сказал, что это фундаментально для Хаскеля, см ф-ию ветвления.
V>>где требуется детерминированная последовательность операций G>Требуется она в одном случае — при общении программы с внешним миром.
Гы, программа без общения с внешним миром не требуется. Есть мнение, что полезный (целевой) эффект от любой программы — исключительно побочный. Поэтому декларативное ТЗ запросто может быть перечислением побочных эффектов.
V>>В общем, иначе было бы гораздо сложнее реализовать исходное императивное ТЗ на чистом ФП, если бы не ленивость. G>О чем ты? Бери F# и Haskell, покажи в чем леность помогает общаться с внешним миром.
Наворачивание ф-ий ввода-вывода на монаду IO в Хаскеле работает именно потому, что ф-ии не вычисляются энергично. Композиция ф-ий образует некий порядок вычислений, который затем пошагово интерпретируется во времени механизмом ленивости как показал выше.
G>И снова напомню что хорошее ТЗ максимально декларативно.
OMG... заберите его от меня...
Я ведь именно это и утверждаю, что суть декларативности — в отделении ТЗ от реализации, независимо от никаких техник реализации. Отвечай тогда уж не мне, а моим оппонентам.
V>>Пришлось бы бороться с комбинаторным взрывом при вычислении (в общем случае рекурсивном) всех аргументов всех операций. И не факт, что программа имела бы останов... G>Это ты о чем вообще? ЧРФ эквивалентны блок-схемам, причем без всякой ленивости
Это я о проблеме останова. О ней, родимой. Блок схемы и описываемая ими пошаговость вносят фактор времени в алгоритм, а ЧРФ никак не вносит. Не умеет... Именно поэтому проблема останова никакая не проблема для современного ПО, сидящего на модели, близкой к МТ. Ну работает себе некий сервис или основной цикл ОС в бесконечном цикле... дык, так и задумывалось.
S>Твои выводы ничего не стоят, т.к. используют термины, смысл которых очевидно искажен.
расскажи, пожалуйста, какой ярлык (декларативный/императивный) ты приклеиваешь к какому языку из списка: sql, c#, haskell. и какие выводы на основе приклеенного ярлыка делаешь?
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, gandjustas, Вы писали:
V>>>Гы, поднимись в определениях на один уровень раньше и посмотри, что есть вычислимая ф-ия. V>>>Своими словами — это та, для которой существует конечная программа в терминах пошаговых инструкций над идеальной машиной (с бесконечной памятью). G>>МТ эквивалента лямбда-исчислению, блок схемам и ЧРФ.
V>Если игнорить проблему останова, которая некритична для императивного вычислителя, например MT, коль программа работает во времени, генерируя при этом пользу
Что значит "некритична"? Что значит "программа работает во времени"? В реальном времени? Любая программа так работает, в языках программирования же никакого времени не существует.
V>Но сия проблема мешает любой энергичной реализации ЧРФ из-за потенциально бесконечного зацикливания (см определение ЧРФ).
Любая программа потенциально зацикливается. Любую незацикливающуюся программу на МТ можно переписать на любом языке и она тоже не будет зацикливаться.
V>А неэнергичная реализация обязательно императивна.
Слова ни о чем. Процессор выполняет последовательность инструкций. Тем не менее оперировать понятием последовательности действий при написании программы не обязательно. И понятие вычислимости функции тоже на "последовательность" не опираются.
G>>Так что можно считать вычислимой функцией ту, которую можно записать в виде ЧРФ. G>>Вычислимость — свойство самой функции, императивность — свойство записи алгоритма вычисления.
V>М/у ними фундаментальная доказанная с разных сторон связь (см теоремы Геделя).
Какая именно, приведи ссылку.
V> Я ведь именно с этим и спорю, что приписать некое св-во одной системе и не приписать эквивалентной другой — банально неграмотно.
Нет, ты пытаешься разные логические уровни объединить в один приписывая свойства объектов одного уровня объектам другого. Это неправильно. Кажется Синклер тебе это уже говорил.
V>>>Ленивость — это изолированный мини-автомат, это та самая классическая ф-ия с памятью, которая и зовется автоматом. Именно ленивость позволяет Хаскелю упорядочить последовательность вычислений, делая их детерминированными, т.е. это именно инструмент детерминированной реализации программы по вышестоящему императивному ТЗ. G>>Прямо немерянное количество заблуждений в одном предложении. G>>1) С чего это ТЗ императивно? Как раз хорошее ТЗ максимально декларативно. То есть не описывает конкретных шагов для получения результата.
V>Дык, ес-но ТЗ декларативно. См. моё определение декларативности.
Давай всетаки общеизвестным пользоваться. http://en.wikipedia.org/wiki/Declarative_programming
V>Просто оно в общем случае описывает эквивалентный автомат, например в терминах use-case... или различные виды описаний каких-нить протоколов и т.д.
Протокол и есть автомат Но это не ТЗ. Вот ТЗ: "стул должен стоять не ближе 5 метров от дивана". Переведи это в автомат.
G>>2) С чего это ленивость- "автомат"? Может у них какие-то общие свойства есть? V>С того, что ф-ий преобразователь с памятью — это и есть автомат, см определение автомата.
Опять ты склеиваешь разные логические уровни. Причем тут память и ленивость? Ты хочешь рассмотреть реализацию ленивости — так и пиши, но не надо после этого приписывать свойства реализации самой ленивости.
G>>Императивный алгоритм — тот который задает последовательность шагов, изменяющих некоторое состояние для достижения результата. Любой императивный алгоритм можно представить в виде структурированой блок-схемы.
V>Ну ок, первую лекцию по программирование за 1-е сентября 1-го курса ты усвоил... Молоток!
А ты?
G>>Ленивость заключается в том что агрументы функции вычисляются не при вызове, а при обращении. Это как раз дает непостоянную последовательность вычисления. То есть как раз в виде блок-схемы записать не получится.
V>Если не знаешь как — спроси. Этот императивный алгоритм над состоянием ленивого преобразователя выражается через две простейшие подпрограммы: V>1. init V>var func = init_func V>var args = init_args V>var result = unknown
V>2. call V>if result is unknown then result = func(args)
И когда будут вычислены args?
например есть программа z = f(x(), y()), вычисления ленивые, преобразуй в блок схемы, указывая последовательность вычислений.
V>Откровенная печаль, что опустились до этого уровня обсуждения... лучше посмотри со стороны... в другой раз отвечать на подобного качества посты я не найду времени, сорри.
Это ты как раз пониматься начал по лестице абстракции, подниись еще чуть выше и посмотри сверху на свою же писанину. Тогда совсем в депрессию впадешь.
V>>>Это такой комбинатор, для которого можно установить необходимый и достаточный порядок вычисления аргументов вместо произвольного. G>>То есть ленивость таки не соответствует фиксированному порядку, а значит не является императивным.
V>Таки комбинатору I приписывается достаточный порядок вычисления аргументов, с тем, чтобы не вычислять часть из них, если уже не требуется. Я бы сказал, что это фундаментально для Хаскеля, см ф-ию ветвления.
"достаточный" не означает фиксированный, это противоречит императивности.
V>>>где требуется детерминированная последовательность операций G>>Требуется она в одном случае — при общении программы с внешним миром.
V>Гы, программа без общения с внешним миром не требуется. Есть мнение, что полезный (целевой) эффект от любой программы — исключительно побочный. Поэтому декларативное ТЗ запросто может быть перечислением побочных эффектов.
И что? Теперь надо обязательно всю программу строить на побочных эффектах?
V>>>В общем, иначе было бы гораздо сложнее реализовать исходное императивное ТЗ на чистом ФП, если бы не ленивость. G>>О чем ты? Бери F# и Haskell, покажи в чем леность помогает общаться с внешним миром.
V>Наворачивание ф-ий ввода-вывода на монаду IO в Хаскеле работает именно потому, что ф-ии не вычисляются энергично.
Не поэтому, кури монады. Можешь в F# повторить state (IO там нет, но суть не отличается).
V>Композиция ф-ий образует некий порядок вычислений, который затем пошагово интерпретируется во времени механизмом ленивости как показал выше.
Тот "механизм" не является полным, потому что он как раз о порядке вычисления агрументов ничего не говорит.
G>>И снова напомню что хорошее ТЗ максимально декларативно. V>OMG... заберите его от меня... V>Я ведь именно это и утверждаю, что суть декларативности — в отделении ТЗ от реализации, независимо от никаких техник реализации. Отвечай тогда уж не мне, а моим оппонентам.
Ты его императивным назвал, а это слово противоречит декларативности.
V>>>Пришлось бы бороться с комбинаторным взрывом при вычислении (в общем случае рекурсивном) всех аргументов всех операций. И не факт, что программа имела бы останов... G>>Это ты о чем вообще? ЧРФ эквивалентны блок-схемам, причем без всякой ленивости
V>Это я о проблеме останова. О ней, родимой.
Она тоже не зависит от ленивости
V>Блок схемы и описываемая ими пошаговость вносят фактор времени в алгоритм, а ЧРФ никак не вносит. Не умеет... Именно поэтому проблема останова никакая не проблема для современного ПО, сидящего на модели, близкой к МТ. Ну работает себе некий сервис или основной цикл ОС в бесконечном цикле... дык, так и задумывалось.
А чем бесконечная рекурсия отличается от бесконечного цикла?
V>>Просто оно в общем случае описывает эквивалентный автомат, например в терминах use-case... или различные виды описаний каких-нить протоколов и т.д. G>Протокол и есть автомат Но это не ТЗ. Вот ТЗ: "стул должен стоять не ближе 5 метров от дивана". Переведи это в автомат.
автомат из одной императивной команды:
установить положение стула не ближе 5 метров от дивана.
Здравствуйте, DarkGray, Вы писали:
G>>Протокол и есть автомат Но это не ТЗ. Вот ТЗ: "стул должен стоять не ближе 5 метров от дивана". Переведи это в автомат.
DG>автомат из одной императивной команды: DG>установить положение стула не ближе 5 метров от дивана.
Здравствуйте, DarkGray, Вы писали:
S>>Этот код не является чисто функциональным, т.к. использует недетерминированные функции.
DG>если уж делаешь какие-то утверждения, то делай это правильно и четко. DG>твоя проблема, что ты умудряешься даже для железобетонных определений делать ужасные формулировки своих утверждений.
DG>точная формулировка: функция конструирующая тип C не является чисто функциональной, т.к. использует недетерминированную функцию new Random(). DG>остальные функции являются чисто функциональными и детерминированными.
Резульаты остальных функций ты воле заменить значениями.
DG>и соответственно, как только ты бы сделал правильное и четкое утверждение, то скорее всего до тебя бы дошло, что тебе показывают и тебя просят подумать про ту часть кода, которая состоит из чисто функциональных детерминированных функциях.
Ты же написал что заменил код на чисто функциональный. Там не было никаких оговорок.
DG>вторая проблема, что ты считаешь собеседников заведомо глупыми. и любую неточность в формулировках ты трактуешь в пользу глупости собеседника, вместо того, чтобы самостоятельно устранить неточность и ответить по существу. при этом ты бы чему-то научился (и это был бы конструктивный подход), а так ты лишь чешешь свое самолюбие.
Я не считаю собеседника глупым. Я считаю что он игнорирует определения. Причем это входит в тенденцию, а значит намеренно.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Этот код не является чисто функциональным, т.к. использует недетерминированные функции.
V>Это ты про Random()? А разве нет его в ФП языках? В примере была демонстрация того, о чем мы тут говорим по всей ветке, забей ты на этот на Random, это уже просто придирки...
Раднома в ФП языках? Именно в таком виде — в чистых нет.
Если забить на рандом, то я не понимаю, в чем суть вопроса. Во втором фрагменте кода побочных эффектов нет
V>Дело в том, что современные компиляторы давно способны устанавливать все зависимости, именно это и позволяет им заниматься оптимизацией и спекулятивным выполнением.
Извиняюсь. Не по делу.
Я почему-то вообще чувствую себя первокурсником, которого пытаются завалить пара преподавателей. Причем особо циничным способом — доказать что я не втыкаю в два определения с первой лекции. И от усердия преподы скатываются черт знает в какие дебри философии. Вот, дело до оптимизации дошло. Но определения-то вот они, в конспекте. Есть другие — давай обсудим. Не вопрос.
S>>Ты молоток, написал кучу кода. Но совершенно зря. Твои выводы ничего не стоят, т.к. используют термины, смысл которых очевидно искажен. Чистота — еще один термин, который ты толкуешь как-то по-своему.
V>Дык более половины встреченных определений "чистоты" неполны. Многие из них вообще говорят о каких-то глобальных переменных, о вводе-выводе и прочий бред... А если у нас нет в языке глобальных переменных? В общем, более нелепого определения чистоты ф-ий, чем в Вики, я еще не видел, так что не мечи тут молнии.
Покажи менее нелепые.
V>Чистота — это отсутствие неявных зависимостей и ничего более. Зачем она вообще нужна? Детерминированности ради. Чистота ведь не самоцель ни разу, а лишь ср-во обеспечения детерминированности. Вернее, одно из ср-в, хотя и самое дешевое из всех. Дешевое в разработке, ес-но... бо в исполнении чистые программы пока ничего дешевого не показывают, скорее наоборот. ИМХО, самое дешевое ср-во обеспечения детерминированности на сегодня по всем показателям суммарно — это локальность состояний. Оно, к тому же, хорошо ложится на современные многоядерные архитектуры.
Какой кошмар.
Смотри: допустим что printf детерминирована. Даже не важно, детерминирована ли она на самом деле, но давай предположим, что да, если на самом деле нет. Пусть она возвращает всегда длину строки, которая могла бы быть выведена вне зависимости ни от чего.
Если ты утверждаешь что она чиста (детерминирована ведь), значит порядок вызова не важен. Верно ли это, ответь мне глядя в консоль на результат работы printf.
Может детерминированности таки мало для чистоты? Если мало, то почему твое определение чистоты лучше чем то что в вики?
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>Зачем же от ленивости-то? Я сейчас с удовольствием почитал собственный аргумент, но в твоей озвучке. Итак... если нет возможности ощутить как-либо побочный эффект, он есть, или его нет? S>>Смотри определение
V>Не в Вики случайно?
Да я там его смотрел. У тебя есть свое, лучше?
S>>Да, Т-полнота для тебя означает вычислимость на МТ, это я уже понял. Хотя по определению Т-полноты это возможность реализовать любую функцию, вычислимую на МТ. S>>Продемонстрируй все-таки побочный эффект от вычисления функции, описанной на хаскеле. Только без бэкдоров типа unsafePerformIO.
V>Да запусти любую программу на хаскеле, да посмотри.
Проблема в том, что результат выполнения main на хаскеле (без использования бэкдоров) является функцией, ну или его можно воспринимать как фукнцию. И увидеть побочный эффект от выполнения main я затрудняюсь. А с тем что эта функция (результат main) может иметь побочные эффекты, я не спорю.
V>>>Просто уже раз 10 говорилось, что порядок выполнения ф-ий можно задать явно, прямо как список инструкций в императивном программировании. А твой "мир" протаскивать как монаду State, например. Получишь выражение одного базиса через другой с идентичным уровнем подробностей. ЧТД. Т.е. никакой базис ни над каким сверху не стоит в отношении "что"->"как", если брать выражение одного через другой. Фундаментально здесь то, что вот это вычисление вложенных ф-ий происходит не одномоментно, а упорядочено, т.е. начинает быть наблюдаемым точно такой же фактор времени, смены стадий вычислений, можно оперировать понятием "контекст вычисления" (см замыкания), что суть мгновенный снимок текущего состояния вычислителя и прочее и прочее. Там всей разницы, что в чистом ФП мы получаем копию вычислителя, а в императивном — оперируем тем же самым. Но! При таких строго последовательных вычислениях (например, без лямбд и продолжений, как в императивном программировании) у нас будет оставаться только копия вычислителя, а оригинал будет все время выкидываться... Вопрос на засыпку: как определить достоверно, что мы выкинули, копию или оригинал? А нельзя ли выкидывать сразу копию? S>>Тебя увело куда-то в сторону. Еще раз. Должен ли результат применения чистых по определению функций зависеть от последовательности их применения?
V>Коль речь о программе целиком, то бишь о композиции ф-ий — ес-но. Именно об этом и речь. Но ты зря скипнул рассуждения и вернулся на самое начало разговора, так мы будем топтаться на месте бесконечно. Уже пора было посмотреть на ООП и другие техники обеспечения локальности побочных эффектов.
Я прочитал еще раз — не заметил в рассуждениях мысли, которая бы была связана с моим вопросом.
V>Мои рассуждения в пред. посте применимы к технике ООП, ведь если объект не имеет зависимостей от глобальных данных, то любые вызовы его методов в однопоточном апартаменте сводятся к эквивалентным чистым
Чушь! V>, по тем рассуждениям что я привел. Потому что все зависимости явные, состояние объекта подается методам на исполнения явно.
Возьмем пример DarkGray-а, где создается объект C, который не зависит ни от каких глобальных данных (напрямую). Но зависит от GetTickCount, который seed в rnd, что данными назвать затруднительно. Тем не менее, считать такой объект чистым — весьма наивно.
Да, пусть объект C имеет зависимость от rnd лишь в конструкторе. Но эта зависимость могла бы быть в методе. И эта зависимость не от данных. Имей в виду, когда будешь карежить определения в другой раз.
S>>Теперь по поводу, нельзя ли выкидывать сразу копию... Копию выкидывать сразу можно при определенных условиях. Но это трюк вычислителя, а не языка программирования. Из того что копия может быть выкинута вычислителем, не следует ровно ничего в отношении императивности языка, описывающего порождение копии.
V>Нет, из этого следует детерминированность, а только она и является целью, а вовсе не абстрактная "чистота".
Напоминаю о примере с якобы детерминированным printf-ом. Детерминированности недостаточно для изменения порядка.
G>>>Протокол и есть автомат Но это не ТЗ. Вот ТЗ: "стул должен стоять не ближе 5 метров от дивана". Переведи это в автомат.
DG>>автомат из одной императивной команды: DG>>установить положение стула не ближе 5 метров от дивана.
S>С понятием автомата ты тоже не знаком?
т.е. ты даже не понимаешь, что такое автомат из одной команды?
Абстра́ктный автома́т (в теории алгоритмов) — математическая абстракция, модель дискретного устройства, имеющего один вход, один выход и в каждый момент времени находящегося в одном состоянии из множества возможных. На вход этому устройству поступают символы одного алфавита, на выходе оно выдаёт символы (в общем случае) другого алфавита.
входной алфавит: стул, для которого должно выполняться условие "стоять не ближе 5 метров от дивана"
выходной алфавит: стул, для которого выполняется условие "стоять не ближе 5 метров от дивана"
входная последовательность: последовательность из одного символа — стул, для которого должно выполняться условие "стоять не ближе 5 метров от дивана"
выходная последовательность: последовательность из одного символа — стул, для которого выполняется условие "стоять не ближе 5 метров от дивана"
автомат имеет три состояния:
инициальное,
рабочее,
терминальное.
стартует с инициального.
из инициального переходит в рабочее.
в рабочем читает один символ алфавита с потока (если символы кончились, то переходит в терминальное),
выполняет команду "установить положение стула не ближе 5 метров от дивана", выдает в поток символ "стул, для которого выполняется условие "стоять не ближе 5 метров от дивана"" и переходит в состояние "рабочее".
G>>>>Протокол и есть автомат Но это не ТЗ. Вот ТЗ: "стул должен стоять не ближе 5 метров от дивана". Переведи это в автомат.
DG>>>автомат из одной императивной команды: DG>>>установить положение стула не ближе 5 метров от дивана.
S>>С понятием автомата ты тоже не знаком?
DG>т.е. ты даже не понимаешь, что такое автомат из одной команды?
DG>
DG>Абстра́ктный автома́т (в теории алгоритмов) — математическая абстракция, модель дискретного устройства, имеющего один вход, один выход и в каждый момент времени находящегося в одном состоянии из множества возможных. На вход этому устройству поступают символы одного алфавита, на выходе оно выдаёт символы (в общем случае) другого алфавита.
DG>выполняет команду "установить положение стула не ближе 5 метров от дивана", выдает в поток символ "стул, для которого выполняется условие "стоять не ближе 5 метров от дивана"" и переходит в состояние "рабочее".
Не знаком ты с понятием автомата. Команды он не выполняет. Символы алфавита — выдает. А команды —
Здравствуйте, DarkGray, Вы писали:
DG>>>остальные функции являются чисто функциональными и детерминированными. S>>Резульаты остальных функций ты воле заменить значениями.
DG>покажи как
Смотришь, чему равно world.c на входе функции, делаешь соответствующие преобразования, получаешь новый World. Этим новым World заменяешь вызов функции.
Отсутствие побочных эффектов (а они там отсутствуют формально), позволяет совершить такую замену.
DG>>и соответственно, как только ты бы сделал правильное и четкое утверждение, то скорее всего до тебя бы дошло, что тебе показывают и тебя просят подумать про ту часть кода, которая состоит из чисто функциональных детерминированных функциях. S>Ты же написал что заменил код на чисто функциональный. Там не было никаких оговорок.
проблема в том, что я постоянно переоцениваю собеседника. и в данном случае ожидал, что ты можешь сам выделить чистофункциональную часть:
class C
{
public C(int x, int y = 0){this.X = x;this.Y = y;}
public readonly int X;
public readonly int Y;
}
class World
{
public int y;
public C c;
}
World F1(World w)
{
C c = new C(w.c.X + 1, w.c.Y);
return new World{c = c, y = w.y - c.X + c.Y};
}
World F2(World w)
{
C c = new C(w.c.X, w.c.Y - 1);
return new World{c = c, y = w.y + c.X + c.Y};
}
World F0(int y1, int y2, C c)
{
return new World{c = c, y = y1 + y2 + (c.X < 0 ? -c.X : c.X);};
}
class YYY
{
public int y1;
public int y2;
public int y3;
}
YYY clean_main(int startX)
{
C c = new C(startX);
var w1 = F1(F2(F1(F1(F1(new World{c = c, y = 7})))));
var w2 = F2(F1(F1(F2(F2(new World{c = w1.c, y = 24})))));
var w3 = F0(w1.y, w2.y, w2.c);
return new YYY{y1 = w1.y, y2 = w2.y, y3 = w3.y};
}
void main()
{
do
startX <- readLn
yyy = clean_main(startX);
PutLine(yyy.y3)
PutLine(yyy.y1)
PutLine(yyy.y2);
}
объясни, пожалуйста, почему в этой функциональной программе в чистой функциональной функции clean_main нельзя поменять местами ни одного вызова, и уж тем более нельзя заменить ни одну функцию на ее значение.
DG>>покажи как S>Смотришь, чему равно world.c на входе функции, делаешь соответствующие преобразования, получаешь новый World. Этим новым World заменяешь вызов функции. S>Отсутствие побочных эффектов (а они там отсутствуют формально), позволяет совершить такую замену.
это общие слова, а ты покажи какую конкретную замену можно сделать в чистой функции clean_main
S>Не знаком ты с понятием автомата. Команды он не выполняет. Символы алфавита — выдает. А команды —
в роботехнике автомат как раз команды исполняет.
можно, конечно, переписать в виде преобразующего автомата, которые преобразует входную последовательность в последовательность команд для исполнительного механизма:
входной алфавит: символ правило1 — стул должен стоять не ближе 5 метров от дивана
выходной алфавит: символ команда1 — установить положение стула не ближе 5 метров от дивана
входная последовательность: последовательность правил
выходная последовательность: последовательность команд для исполнительного механизма
автомат имеет три состояния:
инициальное,
рабочее,
терминальное.
стартует с инициального.
из инициального переходит в рабочее.
в рабочем читает один символ алфавита с потока (если символы кончились, то переходит в терминальное состояние),
для символа правило1 выдает на выход символ команда1 и переходит в состояние "рабочее".
в терминальном состояние автомат останавливается
DG>>>и соответственно, как только ты бы сделал правильное и четкое утверждение, то скорее всего до тебя бы дошло, что тебе показывают и тебя просят подумать про ту часть кода, которая состоит из чисто функциональных детерминированных функциях. S>>Ты же написал что заменил код на чисто функциональный. Там не было никаких оговорок.
DG>проблема в том, что я постоянно переоцениваю собеседника. и в данном случае ожидал, что ты можешь сам выделить чистофункциональную часть:
Я не посмел, ты ведь написал что сделал эквивалентный чисто функциональный код.
DG>
DG>class C
DG>{
DG> public C(int x, int y = 0){this.X = x;this.Y = y;}
DG> public readonly int X;
DG> public readonly int Y;
DG>}
DG>class World
DG>{
DG> public int y;
DG> public C c;
DG>}
DG>World F1(World w)
DG>{
DG> C c = new C(w.c.X + 1, w.c.Y);
DG> return new World{c = c, y = w.y - c.X + c.Y};
DG>}
DG>World F2(World w)
DG>{
DG> C c = new C(w.c.X, w.c.Y - 1);
DG> return new World{c = c, y = w.y + c.X + c.Y};
DG>}
DG>World F0(int y1, int y2, C c)
DG>{
DG> return new World{c = c, y = y1 + y2 + (c.X < 0 ? -c.X : c.X);};
DG>}
DG>class YYY
DG>{
DG> public int y1;
DG> public int y2;
DG> public int y3;
DG>}
DG>YYY clean_main(int startX)
DG>{
DG> C c = new C(startX);
DG> var w1 = F1(F2(F1(F1(F1(new World{c = c, y = 7})))));
DG> var w2 = F2(F1(F1(F2(F2(new World{c = w1.c, y = 24})))));
DG> var w3 = F0(w1.y, w2.y, w2.c);
DG> return new YYY{y1 = w1.y, y2 = w2.y, y3 = w3.y};
DG>}
DG>void main()
DG>{
DG> do
DG> startX <- readLn
DG> yyy = clean_main(startX);
DG> PutLine(yyy.y3)
DG> PutLine(yyy.y1)
DG> PutLine(yyy.y2);
DG>}
DG>
DG>объясни, пожалуйста, почему в этой функциональной программе
Программа не чисто функциональна, кури бамбук (можешь считать это ответом на переоценку собеседника ). DG>в чистой функциональной функции clean_main нельзя поменять местами ни одного вызова, и уж тем более нельзя заменить ни одну функцию на ее значение.
Потому что вычисления аргументов для очередного вызова завязаны на результат предыдущих вызовов. Но ты не расслабляйся. Судя по языку, я не смог его отнести к какому-то конкретному, потому вызывает сомнения порядок редукции в этом языке. Возможно его можно сменить, тогда изменится порядок вызовов. Возможно это не повлияет на побочный эффект от программы.
ЗЫ. На месте компилятора такого чисто функционального языка я бы оставил void main(){} на основе чистоты.
DG>>>покажи как S>>Смотришь, чему равно world.c на входе функции, делаешь соответствующие преобразования, получаешь новый World. Этим новым World заменяешь вызов функции. S>>Отсутствие побочных эффектов (а они там отсутствуют формально), позволяет совершить такую замену.
DG>это общие слова, а ты покажи какую конкретную замену можно сделать в чистой функции clean_main
Я отвечал до того как увидел твой новый кусок кода с clean_main
S>>Не знаком ты с понятием автомата. Команды он не выполняет. Символы алфавита — выдает. А команды —
DG>в роботехнике автомат как раз команды исполняет.
Очень ценное замечание. А в армии он стреляет.
DG>можно, конечно, переписать в виде преобразующего автомата, которые преобразует входную последовательность в последовательность команд для исполнительного механизма:
Теперь
DG>входной алфавит: символ правило1 — стул должен стоять не ближе 5 метров от дивана DG>выходной алфавит: символ команда1 — установить положение стула не ближе 5 метров от дивана DG>входная последовательность: последовательность правил DG>выходная последовательность: последовательность команд для исполнительного механизма DG>автомат имеет три состояния: DG>инициальное, DG>рабочее, DG>терминальное. DG>стартует с инициального. DG>из инициального переходит в рабочее. DG>в рабочем читает один символ алфавита с потока (если символы кончились, то переходит в терминальное состояние), DG>для символа правило1 выдает на выход символ команда1 и переходит в состояние "рабочее". DG>в терминальном состояние автомат останавливается
Возникает вопрос о целеобразности такого автомата, ну да фиг с ним.
S>Возникает вопрос о целеобразности такого автомата, ну да фиг с ним.
о том и речь, что все зависит от набора команд, поддержанных исполнительным механизмом (или что тоже самое, от вида исполнителя).
и что если не зафиксирован исполнитель (в виде поддержанного им набора команд), то делать какие-то утверждения бессмысленно, и уж тем более бессмысленно делать заявления о декларативности или императивности управляющего языка.
DG>>в роботехнике автомат как раз команды исполняет. S>Очень ценное замечание. А в армии он стреляет.
речь идет о том, что автоматов как грязи: с двумя входными лентами, с тремя входными, с двумя выходными, с десятью выходными, с ячейками памяти, с лентами памяти и т.д.
все они эквиваленты между собой, а также эквивалентны машине тьюринга.
и при набитой руке правила для преобразования одного автомата в другой генерятся за пару минут, и поэтому в каждом конкретном случае используется тот вид автомата, который удобнее.
предыдущий автомат с командами — это автомат с двумя выходными лентами: лента выходного результа + лента команд.
S>>Возникает вопрос о целеобразности такого автомата, ну да фиг с ним.
DG>о том и речь, что все зависит от набора команд, поддержанных исполнительным механизмом (или что тоже самое, от вида исполнителя).
Не понимаю, что такое вид исполнителя и как он меняется от изменения набора команд.
DG>и что если не зафиксирован исполнитель (в виде поддержанного им набора команд), то делать какие-то утверждения бессмысленно, и уж тем более бессмысленно делать заявления о декларативности или императивности управляющего языка.
И все-таки, как связана декларативность языка с исполнителем?
DG>>>в роботехнике автомат как раз команды исполняет. S>>Очень ценное замечание. А в армии он стреляет.
DG>речь идет о том, что автоматов как грязи: с двумя входными лентами, с тремя входными, с двумя выходными, с десятью выходными, с ячейками памяти, с лентами памяти и т.д. DG>все они эквиваленты между собой, а также эквивалентны машине тьюринга. DG>и при набитой руке правила для преобразования одного автомата в другой генерятся за пару минут, и поэтому в каждом конкретном случае используется тот вид автомата, который удобнее.
DG>предыдущий автомат с командами — это автомат с двумя выходными лентами: лента выходного результа + лента команд.
Я так понимаю, ты о каких-то своих автоматах, не о том, который математическая абстракция. Извини, сразу не понял.
Здравствуйте, DarkGray, Вы писали:
S>>Потому что вычисления аргументов для очередного вызова завязаны на результат предыдущих вызовов.
DG>это хорошо или плохо?
Шуруповерт — это хорошо или плохо? Я так думаю, что шуруповертом хорошо заворачивать шурупы. А чистить уши — плохо. Вот и композиция функций — это инструмент.
DG>и можно ли для этой программы сделать так, чтобы завязок не было или было меньше?
Это ты мне скажи. Ты же автор исходной программы. Я так и не понял, что же она должна делать кроме демонстрации "побочного эффекта" в "чистых" функциях, с которая с треском провалилась, как я считаю.
V>>>Просто оно в общем случае описывает эквивалентный автомат, например в терминах use-case... или различные виды описаний каких-нить протоколов и т.д. G>>Протокол и есть автомат Но это не ТЗ. Вот ТЗ: "стул должен стоять не ближе 5 метров от дивана". Переведи это в автомат.
DG>автомат из одной императивной команды: DG>установить положение стула не ближе 5 метров от дивана.
DG>>предыдущий автомат с командами — это автомат с двумя выходными лентами: лента выходного результа + лента команд. S>Я так понимаю, ты о каких-то своих автоматах, не о том, который математическая абстракция. Извини, сразу не понял.
S>>>Потому что вычисления аргументов для очередного вызова завязаны на результат предыдущих вызовов.
DG>>это хорошо или плохо? S>Шуруповерт — это хорошо или плохо? Я так думаю, что шуруповертом хорошо заворачивать шурупы. А чистить уши — плохо. Вот и композиция функций — это инструмент.
ты же по специальности программист? верно?
при этом получается, что ты смог дать наивное пояснение про шуруповерт (который к программированию не имеет никакого отношения) — для каких задач шуруповерт является хорошим инструментом, а для каких не очень (правда скорее всего это опять же не твое понимание, а лишь цитата какого-нибудь авторитета из инструкции к шуруповерту).
а по своей специальности, ты не смог сформулировать даже наивное пояснение, чем хороши (или плохи) завязки между вызовами функциями и при каких условиях. Это к теме, кого сейчас берут в программисты..
V>>>>Просто оно в общем случае описывает эквивалентный автомат, например в терминах use-case... или различные виды описаний каких-нить протоколов и т.д. G>>>Протокол и есть автомат Но это не ТЗ. Вот ТЗ: "стул должен стоять не ближе 5 метров от дивана". Переведи это в автомат.
DG>>автомат из одной императивной команды: DG>>установить положение стула не ближе 5 метров от дивана.
G>А толку?
при наличии исполнителя, который умеет выполнять эту команду — такого автомата достаточно.
DG>>>предыдущий автомат с командами — это автомат с двумя выходными лентами: лента выходного результа + лента команд. S>>Я так понимаю, ты о каких-то своих автоматах, не о том, который математическая абстракция. Извини, сразу не понял.
DG>понаберут народ на форумы по объявлениям...
DG>это как раз и есть всё математические автоматы, и в приличных вузах на курсе "теории автоматов" (http://ru.wikipedia.org/wiki/%D2%E5%EE%F0%E8%FF_%E0%E2%F2%EE%EC%E0%F2%EE%E2) их как раз и изучают, и переводы одних видов автоматов в другие.
DG>
DG>Синтез автоматов — построение системы из заданных «элементарных автоматов», эквивалентную заданному автомату. Такой автомат называется структурным.
DG>автомат с двумя выходными лентами — это и есть структурный автомат, состоящий, например, из трех элементарных автоматов
Теорию автоматов нам читали, но автомат с двумя выходными лентами я что-то не припомню. Может и просто запамятовал. Но склоняюсь к тому что выдумал его ты.
S>>>>Потому что вычисления аргументов для очередного вызова завязаны на результат предыдущих вызовов.
DG>>>это хорошо или плохо? S>>Шуруповерт — это хорошо или плохо? Я так думаю, что шуруповертом хорошо заворачивать шурупы. А чистить уши — плохо. Вот и композиция функций — это инструмент.
DG>ты же по специальности программист? верно?
Нет. Математик.
DG>при этом получается, что ты смог дать наивное пояснение про шуруповерт (который к программированию не имеет никакого отношения) — для каких задач шуруповерт является хорошим инструментом, а для каких не очень (правда скорее всего это опять же не твое понимание, а лишь цитата какого-нибудь авторитета из инструкции к шуруповерту).
DG>а по своей специальности, ты не смог сформулировать даже наивное пояснение, чем хороши (или плохи) завязки между вызовами функциями и при каких условиях. Это к теме, кого сейчас берут в программисты..
Я не знаю, кто ты по специальности, но твои наивные пояснения отношения используемых тобой терминов к общепринятым меня не устраивают. Выдавать тебе такую же бурду в отношении композиции функций я не собираюсь.
Здравствуйте, DarkGray, Вы писали:
S>>>>Возникает вопрос о целеобразности такого автомата, ну да фиг с ним.
DG>>>о том и речь, что все зависит от набора команд, поддержанных исполнительным механизмом (или что тоже самое, от вида исполнителя). S>>Не понимаю, что такое вид исполнителя и как он меняется от изменения набора команд.
DG>есть вид исполнителя: процессор x86, DG>есть вид исполнителя: реляционная субд с поддержкой sql, DG>есть вид исполнителя: стековая машина с модулем АЛУ и ФПУ, DG>есть вид исполнителя: .net, DG>есть вид исполнителя: .net с набором библиотек для заданной тематики, DG>есть вид исполнителя: haskell, DG>есть вид исполнителя: "человек с тремя классами образования", DG>есть вид исполнителя: человек-специалист в заданной тематике. DG>и т.д.
Т.е. виды исполнителей отличаются наименованием что ли?
DG>каждый из них обладает своим набором поддерживаемых команд, если этот набор последовательно менять (добавляя/убавляя по команде), то произойдет переход к другому виду исполнителя.
Это какая-то магия
DG>>>и что если не зафиксирован исполнитель (в виде поддержанного им набора команд), то делать какие-то утверждения бессмысленно, и уж тем более бессмысленно делать заявления о декларативности или императивности управляющего языка. S>>И все-таки, как связана декларативность языка с исполнителем?
DG>напрямую (и ты это увидишь, как только определение из той же вики переведешь к математическому виду)
Ты его уже привел? Можно взглянуть?
DG>например, для исполнителя samius конструкция "автомат из одной команды Z" есть императивная программа, которую он понимает только если рядом приложена пошаговая инструкция, как из этой конструкции перейти к поддерживаемому им набору команд, в частности, к автомату математическому классическому.
Я не понял, что ты написал
DG>большая часть сказанного в треде воспринимается также императивно: понятно пока есть инструкция — как это понимать; при наличии малейших отклонений в условии — ступор и выдача ошибки.
Большую часть сказанного тобой в этом треде я по-началу пытался воспринимать, теперь уже скорее нет, чем да. Я лишь занимаюсь тем, что тыкаю тебя в определения. Какой смысл пытаться что-то понимать, если ты используешь другую терминологию? Ты ведь так и не ответил. Так что я продолжаю развлекаться.
DG>не делает видимых попыток перехода к декларативному мышлению: фиксирование требований к результату с последующим выбором наилучших инструментов для достижения поставленной цели.
Декларативное мышление?
Теперь начинаю понимать
Здравствуйте, gandjustas, Вы писали: G>А толку?
Ну, парни тут явно считают программу "найди такой целый x, чтобы x^3 был равен сумме y^3+z^3, где z и y — целые" императивной. Лишь бы исполнитель был подходящий.
Думаю, дальше смысла обсуждать нет.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>автомат с двумя выходными лентами — это и есть структурный автомат, состоящий, например, из трех элементарных автоматов
S>Теорию автоматов нам читали, но автомат с двумя выходными лентами я что-то не припомню. Может и просто запамятовал. Но склоняюсь к тому что выдумал его ты.
так и не надо его припоминать, это все равно что припоминать сколько будет 238 * 174. Необходимо уметь строить произвольный автомат с заданными свойствами под конкретную задачу на основе элементарных автоматов.
V>>>>>Просто оно в общем случае описывает эквивалентный автомат, например в терминах use-case... или различные виды описаний каких-нить протоколов и т.д. G>>>>Протокол и есть автомат Но это не ТЗ. Вот ТЗ: "стул должен стоять не ближе 5 метров от дивана". Переведи это в автомат.
DG>>>автомат из одной императивной команды: DG>>>установить положение стула не ближе 5 метров от дивана.
G>>А толку?
DG>при наличии исполнителя, который умеет выполнять эту команду — такого автомата достаточно.
Ключевое слово "подходящий". Сразу понятно что не любой, так как постановка задачи не предполагает конкретного порядка исполнения. Это и есть декларативность.
Программа в императивном стиле может быть исполнена самым тупым исполнителем, например процессором.
G>Ключевое слово "подходящий". Сразу понятно что не любой, так как постановка задачи не предполагает конкретного порядка исполнения. Это и есть декларативность.
не существует общего алгоритма для измерения "в задаче задан порядок исполнения или не задан".
а раз нет алгоритма, то и не существует объективного способа утверждать данная конструкция декларативна или императивна.
есть лишь субьективные мнения, которые могут быть различны и зависят лишь от личных предпочтений.
G>Программа в императивном стиле может быть исполнена самым тупым исполнителем, например процессором.
вот ты сейчас предлагаешь уже конструктивное определение для понятия "императивный стиль" (и кстати в этом утверждении уже появился конкретный исполнитель), которое уже как-то измеримо.
тогда появляется система утверждений:
у1. для всякой императивной программы известен алгоритм, который позволяет эту программу выполнить с помощью процессора x86 за предсказуемое время с потреблением предсказуемого кол-ва ресурсов.
у2. не для всякой декларативной программы известен алгоритм, который позволяет эту программу выполнить с помощью процессора (и далее по тексту)
что даем нам индикатор:
у3. если для программы известен алгоритм, позволяющий выполнить ее с помощью процессора x86, то с большей вероятностью, она принадлежит к классу императивных программ.
вопросы:
в1. классификация декларативная/императивная используется
двузначная (всякая программа обязана принадлежать ровно к одному классу: декларативная/императивная),
трехзначная (всякая программа обязана принадлежать ровно к одному классу: декларативная/императивная/неизвестно),
четырехзначная (всякая программа обязана принадлежать ровно к одному классу: только декларативная/только императивная/неизвестно/и декларативная, и императивная одновременно)
в2. является ли пункт у1 достаточным, чтобы программу отнести к классу императивный?
в3. является ли пункт у1 необходимым, чтобы программу отнести к классу императивный?
G>>А толку? S>Ну, парни тут явно считают программу "найди такой целый x, чтобы x^3 был равен сумме y^3+z^3, где z и y — целые" императивной. Лишь бы исполнитель был подходящий. S>Думаю, дальше смысла обсуждать нет.
samius не смог ответить — спрошу тебя.
какие выводы можно сделать из утверждения: программа "найди такой целый x, чтобы x^3 был равен сумме y^3+z^3, где z и y — целые" — является декларативной?
или другими словами: отнесение программы к декларативной или императивной, это есть задача классификации, а всякая нетривиальная классификация обладает следствием: у каждого класса есть свои свойства, которые не проявляются у других классов.
соответственно, вопрос: после того, как ты отнес программу "найди такой целый x, чтобы x^3 был равен сумме y^3+z^3, где z и y — целые" к классу декларативная, какие свойства у данной программы появились? (вопрос в конструктивной логике, а не в логике существования)
G>>Ключевое слово "подходящий". Сразу понятно что не любой, так как постановка задачи не предполагает конкретного порядка исполнения. Это и есть декларативность.
DG>не существует общего алгоритма для измерения "в задаче задан порядок исполнения или не задан".
Да, поэтому понятие императивности связано с используемым языком описания.
DG>а раз нет алгоритма, то и не существует объективного способа утверждать данная конструкция декларативна или императивна.
Для конкретного языка вполне можно утверждать. Например для русского.
G>>Программа в императивном стиле может быть исполнена самым тупым исполнителем, например процессором. DG>вот ты сейчас предлагаешь уже конструктивное определение для понятия "императивный стиль" (и кстати в этом утверждении уже появился конкретный исполнитель), которое уже как-то измеримо.
Исполнителя заметь ты выдумал. Хотя для любого ТЗ (алгоритма) есть исполнитель.
DG>тогда появляется система утверждений: DG>у1. для всякой императивной программы известен алгоритм, который позволяет эту программу выполнить с помощью процессора x86 за предсказуемое время с потреблением предсказуемого кол-ва ресурсов. DG>у2. не для всякой декларативной программы известен алгоритм, который позволяет эту программу выполнить с помощью процессора (и далее по тексту)
Без рассмотрения языка смысла не имеет. Как выполнить императивный алгоритм на русском языке с помощью процессора x86?
1) Подойди к стулу
2) Подними стул
3) Если ты стоишь дальше 5 метров от дивана, то подойди к дивану, если ближе, то отойди.
4) Поставь стул
DG>что даем нам индикатор: DG>у3. если для программы известен алгоритм, позволяющий выполнить ее с помощью процессора x86, то с большей вероятностью, она принадлежит к классу императивных программ.
Мощность языков программирования по тьюрингу одинакова и они все выполняются на x86 процессорах. Так что фраза твоя ни о чем.
Еще раз: императивность свойство записи алгоритма. Программа на C будет императивна, а на хаскеле декларативна, а обе считают числа фибоначчи.
Здравствуйте, DarkGray, Вы писали:
G>>Ключевое слово "подходящий". Сразу понятно что не любой, так как постановка задачи не предполагает конкретного порядка исполнения. Это и есть декларативность.
DG>не существует общего алгоритма для измерения "в задаче задан порядок исполнения или не задан".
Это ты намекаешь на жесткость порядка вызова для композиции функций? Его нет. Можно начать со внешней функции, можно со внутренней.
DG>а раз нет алгоритма, то и не существует объективного способа утверждать данная конструкция декларативна или императивна.
Алгоритм? Есть определение. Открой его для себя наконец.
G>>Программа в императивном стиле может быть исполнена самым тупым исполнителем, например процессором.
DG>вот ты сейчас предлагаешь уже конструктивное определение для понятия "императивный стиль" (и кстати в этом утверждении уже появился конкретный исполнитель), которое уже как-то измеримо.
DG>тогда появляется система утверждений: DG>у1. для всякой императивной программы известен алгоритм, который позволяет эту программу выполнить с помощью процессора x86 за предсказуемое время с потреблением предсказуемого кол-ва ресурсов.
int x = 1;
for (;;)
{
x = -x;
}
Надо полагать что програма выше не императивна, или таки известен алгоритм, который позволит выполнить ее с помощью x86 за предсказуемое время?
Какую же ты чушь выдумываешь
DG>>а раз нет алгоритма, то и не существует объективного способа утверждать данная конструкция декларативна или императивна. G>Для конкретного языка вполне можно утверждать. Например для русского.
приведи алгоритм, как для программы на русском языке измерить относится она к классу: декларативная или императивная?
G>>>Программа в императивном стиле может быть исполнена самым тупым исполнителем, например процессором. DG>>вот ты сейчас предлагаешь уже конструктивное определение для понятия "императивный стиль" (и кстати в этом утверждении уже появился конкретный исполнитель), которое уже как-то измеримо. G>Исполнителя заметь ты выдумал. Хотя для любого ТЗ (алгоритма) есть исполнитель.
одно с другими не стыкуется. двумя строчками выше в твоей фразе написано слово "исполнитель". оно туда случайно попало?
DG>>тогда появляется система утверждений: DG>>у1. для всякой императивной программы известен алгоритм, который позволяет эту программу выполнить с помощью процессора x86 за предсказуемое время с потреблением предсказуемого кол-ва ресурсов. DG>>у2. не для всякой декларативной программы известен алгоритм, который позволяет эту программу выполнить с помощью процессора (и далее по тексту) G>Без рассмотрения языка смысла не имеет. Как выполнить императивный алгоритм на русском языке с помощью процессора x86? G>1) Подойди к стулу G>2) Подними стул G>3) Если ты стоишь дальше 5 метров от дивана, то подойди к дивану, если ближе, то отойди. G>4) Поставь стул
например, взять алгоритм которые русские слова переводит в слова языка python.
Проблема может быть с понятиями (а не словами), вернее даже с распознаванием образов (как распознать, какой объект реального мира соответствует понятию "стул"?) — и соответственно всё упрется в исполнителя (умеет он или нет выделять объекты стул и диван из окружающего мира), при этом если утверждается, что умеет, потому что на каждый стул и диван приклеена бирка с поясняющим штрихкодом (или может речь вообще про растановку мебели внутри виртуальной комнаты), то эту программу осилит и процессов x86.
DG>>что даем нам индикатор: DG>>у3. если для программы известен алгоритм, позволяющий выполнить ее с помощью процессора x86, то с большей вероятностью, она принадлежит к классу императивных программ. G>Мощность языков программирования по тьюрингу одинакова и они все выполняются на x86 процессорах. Так что фраза твоя ни о чем.
эта эквивалентность не обещает, что алгоритм после преобразования останется вычислимым за заданное время.
например, склейка двух списков, которая для исполнителя с произвольным доступом к памяти занимает O(1), для исполнителя — чистое ФЯ без ленивости — O(N), для МТ-исполнителя — уже будет O(N^2).
соответственно, если есть алгоритм для списков, который требует N операций склейки списков, для первого случая даст O(N), для второго O(N^2), а для третьего O(N^3)
первый исполнитель может применять такой алгоритм примерно до N=10^12, второй до N=10^6, третий до N=10^4
в итоге, на практике на разных исполнителях за заданное время можно решить разные наборы задач.
G> Программа на C будет императивна, а на хаскеле декларативна, а обе считают числа фибоначчи.
какое это дает различие?
следует ли из этого, например, что компилятору C запрещается на основе своей версии программы заменять расчет числа фибоначчи на конечное число?
DG>>а раз нет алгоритма, то и не существует объективного способа утверждать данная конструкция декларативна или императивна. S>Алгоритм? Есть определение. Открой его для себя наконец.
не всякое определение является конструктивным, или другими словами не всякое определение эквивалентно алгоритму.
определение декларативности не является конструктивным (и не имеет эквивалентного алгоритма для отнесения конкретной программы, конкретного языка к декларативным или нет).
S>Надо полагать что програма выше не императивна, или таки известен алгоритм, который позволит выполнить ее с помощью x86 за предсказуемое время?
какие следствия хочется получить от классификации бессмысленных программ — это уже отдельный вопрос.
G>Напиши проще: понимает ли исполнитель язык. Я тебе об этом и толкую, что без языка нет смысла обсуждать. И совершенно необязательно это должен быть формальный язык или машинный язык.
что такое "понимает язык"? процессор x86 язык C понимает или не понимает? это не конструктивное определение, а опять же вкусовщина.
конструктивное определение — исполнитель Z поддерживает язык L, если существует алгоритм, который переводит язык L в набор команд поддерживаемый исполнителем Z.
DG>эта эквивалентность не обещает, что алгоритм после преобразования останется вычислимым за заданное время. G> А причем тут время? Мы про время еще ничего не говорили. Не надо лишние, для понимания сути, вещи включать.
если не брать время, то из эквивалентности языка C и языка haskell следует, что программу на языке C можно автоматически перевести на язык haskell, и соответственно любую императивную программу на языке C можно автоматически представить в декларативном виде.
DG>>>а раз нет алгоритма, то и не существует объективного способа утверждать данная конструкция декларативна или императивна. S>>Алгоритм? Есть определение. Открой его для себя наконец.
DG>не всякое определение является конструктивным, или другими словами не всякое определение эквивалентно алгоритму. DG>определение декларативности не является конструктивным (и не имеет эквивалентного алгоритма для отнесения конкретной программы, конкретного языка к декларативным или нет).
Сходи по ссылке на определение. Увидь в нем ссылку на поток управления. Прочитай о потоке управления. Поищи признаки потока управления в программе. Если найдешь — значит императив.
Так достаточно императивно для тебя? Нужно ли писать инструкции для узнавания конструкций потока управления?
S>>Надо полагать что програма выше не императивна, или таки известен алгоритм, который позволит выполнить ее с помощью x86 за предсказуемое время?
DG>какие следствия хочется получить от классификации бессмысленных программ — это уже отдельный вопрос.
Отчего бессмысленных? Ее смысл заключается в том, что бы показать что твое утверждение чушь. Во всяком случае смысла в ней не меньше, чем в твоей последней.
Могу написать императивную программу со смыслом, которая за конечное время x86 не выполнится. От этого ведь ничего не изменится. Твое утверждение останется чушью. Так что вопрос классификации бессмысленных программ можно не отделять.
Здравствуйте, DarkGray, Вы писали:
G>>Напиши проще: понимает ли исполнитель язык. Я тебе об этом и толкую, что без языка нет смысла обсуждать. И совершенно необязательно это должен быть формальный язык или машинный язык.
DG>что такое "понимает язык"? процессор x86 язык C понимает или не понимает? это не конструктивное определение, а опять же вкусовщина. DG>конструктивное определение — исполнитель Z поддерживает язык L, если существует алгоритм, который переводит язык L в набор команд поддерживаемый исполнителем Z.
Следующим шагом будет то, что декларативные программы, это те, для которых не существует алгоритма перевода в язык MT?
DG>>эта эквивалентность не обещает, что алгоритм после преобразования останется вычислимым за заданное время. G>> А причем тут время? Мы про время еще ничего не говорили. Не надо лишние, для понимания сути, вещи включать.
DG>если не брать время, то из эквивалентности языка C и языка haskell следует, что программу на языке C можно автоматически перевести на язык haskell, и соответственно любую императивную программу на языке C можно автоматически представить в декларативном виде.
Мутишь воду. Равная мощность языков по Тьюрингу не означает возможность автоматического перевода. Определение читал?
S>>Так достаточно императивно для тебя? Нужно ли писать инструкции для узнавания конструкций потока управления?
DG>напиши, пожалуйста. DG> сразу с алгоритмом, как отличать императивный аналог из C от декларативного аналога из haskell.
Напиши мне тогда, что является аналогом перехода в хаскеле, условного перехода, аналогом цикла, halt-а и т.п.
Здравствуйте, DarkGray, Вы писали:
G>>Напиши проще: понимает ли исполнитель язык. Я тебе об этом и толкую, что без языка нет смысла обсуждать. И совершенно необязательно это должен быть формальный язык или машинный язык.
DG>что такое "понимает язык"?
То есть для него предложение на языке не является бессвязным набором символов.
DG>процессор x86 язык C понимает или не понимает?
Не понимает, но понимает копилятор, а так как язык формален, то есть однозначное отображение на x86.
Можешь считать что понимает. А вот русский язык не понимает.
Но это никак не относится к императивности и декларативности.
DG>это не конструктивное определение, а опять же вкусовщина. DG>конструктивное определение — исполнитель Z поддерживает язык L, если существует алгоритм, который переводит язык L в набор команд поддерживаемый исполнителем Z.
Это ты придумал исполнителя и начал все усложнять. Я же говорю тебе что не стоит.
DG>>эта эквивалентность не обещает, что алгоритм после преобразования останется вычислимым за заданное время. G>> А причем тут время? Мы про время еще ничего не говорили. Не надо лишние, для понимания сути, вещи включать.
DG>если не брать время, то из эквивалентности языка C и языка haskell следует, что программу на языке C можно автоматически перевести на язык haskell, и соответственно любую императивную программу на языке C можно автоматически представить в декларативном виде.
Не получится, программа на C содержит слишком мало сведений чтобы сделать её декларативной автоматически. А вот наоборот — вполне. Более того императивную программу на haskell (завернутое в IO) не получится автоматически переписать в декларативную программу на haskell.
S>Мутишь воду. Равная мощность языков по Тьюрингу не означает возможность автоматического перевода. Определение читал?
если не требуется сохранить время выполнения, то означает.
для перевода языка L1 в язык L2 без сохранения времени выполнения программы достаточно:
1. на языке L2 иметь компилируемый эмулятор языка L3 стековой машины (или, например, эмулятор asm x86),
2. иметь транслятор с языка L1 на язык L3 стековой машины(или, например, asm x86)
программа на языке L1 транслятором переводится в листинг L3, который переводится в листинг языка L1.
Здравствуйте, DarkGray, Вы писали: DG>или другими словами: отнесение программы к декларативной или императивной, это есть задача классификации, а всякая нетривиальная классификация обладает следствием: у каждого класса есть свои свойства, которые не проявляются у других классов. DG>соответственно, вопрос: после того, как ты отнес программу "найди такой целый x, чтобы x^3 был равен сумме y^3+z^3, где z и y — целые" к классу декларативная, какие свойства у данной программы появились? (вопрос в конструктивной логике, а не в логике существования)
После отнесения никакие свойства, конечно же, не появились. Вот мы отнесли воду к классу "жидкости". У неё что, появились какие-то свойства? Нет, они были и до этого.
Мне лично кажется, что классификация выполняется на основе наличия либо отсутствия каких-либо свойств.
В частности, приведённая программа не обладает свойством быть выраженной в терминах последовательного изменения состояния некоторого вычислителя.
Однократного изменения состояния (из "не знаю ответ" в "знаю ответ") недостаточно для того, чтобы считать программу императивной.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>После отнесения никакие свойства, конечно же, не появились. Вот мы отнесли воду к классу "жидкости". У неё что, появились какие-то свойства? Нет, они были и до этого.
это в логике существования. когда используется, что свойства чего-либо существуют без нашего знания о них, но проблема в том, что как тогда эти свойства на практике использовать, если мы о них не знаем?
соответственно, рекомендуется утверждения строить в конструктивной логике (а не в логике существования), и тогда свойства появляются как результат выводов из предыдущих утверждений
например, для числа 2^2012^2012 — 1 мы знаем, что существует классификация: оно либо простое либо нет, либо делиться на три, либо нет.
но пока у нас нет алгоритма, который может это проверить, появляется третий вариант — еще не знаем.
и утверждается, что если мы классифицируем это число, как имеющее нулевой остаток от целочисленного деления на 3, тогда это число будет обладать свойством, что оно непростое.
S>После отнесения никакие свойства, конечно же, не появились. Вот мы отнесли воду к классу "жидкости". У неё что, появились какие-то свойства? Нет, они были и до этого.
они были, но мы о них не знали.
если мы относим воду к классу "жидкость", то мы тогда получаем знание о свойствах:
вода имеет свойства: текучесть, сохраняние объема, вязкость и т.д. по списку физические свойства жидкости: http://ru.wikipedia.org/wiki/%C6%E8%E4%EA%EE%F1%F2%FC
так же можем осторожно делать вывод, что вода не твердая, и не газообразная.
S>Мне лично кажется, что классификация выполняется на основе наличия либо отсутствия каких-либо свойств. S>В частности, приведённая программа не обладает свойством быть выраженной в терминах последовательного изменения состояния некоторого вычислителя. S>Однократного изменения состояния (из "не знаю ответ" в "знаю ответ") недостаточно для того, чтобы считать программу императивной.
не обладает свойством быть выраженной — это нельзя построить алгоритм, который переводит эту программу в последовательность изменения состояния некоторого вычислителя?
но для haskell-я и sql-я такой алгоритм есть, это означает что haskell и sql — императивные?
S>>В частности, приведённая программа не обладает свойством быть выраженной в терминах последовательного изменения состояния некоторого вычислителя.
кстати, может ты хотел добавить про конечность алгоритма.
программу про кубы можно представить в виде бесконечного алгоритма последовательного перебора значений (x0, y0), (x0+1, y0), (x0+1, y0+1), (x0+2, y0+1) и т.д.
DG>деление на декларативный и императивный код появилось на заре становления программирования при решении задачи: может ли меняться код исполнения при той или иной записи программы? и в какой степени?
тоже самое можно переформулировать в конструктивную форму:
если для программы можно построить несколько способов исполнения, то программа является декларативной, иначе императивной.
но сейчас с появлением оптимизирующих исполнителей для чего угодно, это определение перестало делить программы на два класса, оно почти все программы запихивает в класс декларативных
соответственно, если хочется продолжать делить языки на два класса, то необходимо поменять этот критерий, и, например, специфицировать как именно подсчитывается кол-во способов исполнения.
G>>Более того императивную программу на haskell (завернутое в IO) не получится автоматически переписать в декларативную программу на haskell.
DG>можно, кстати, пример применения реальной программы на хаскеле, которая не использует монаду IO (или ее аналог)
Нет, потому что main::IO()
Отказаться от побочных эффектов нельзя. Вся суть любой программы в побочных эффектах. Но сделать так чтобы побочные эффекты были только там где необходимы стремятся все.
Здравствуйте, DarkGray, Вы писали:
DG>это в логике существования. когда используется, что свойства чего-либо существуют без нашего знания о них, но проблема в том, что как тогда эти свойства на практике использовать, если мы о них не знаем?
Не вижу проблемы. Свойства существуют независимо от нашего знания о них. Чтобы использовать на практике их, естественно, нужно узнать.
DG>они были, но мы о них не знали. DG>если мы относим воду к классу "жидкость", то мы тогда получаем знание о свойствах.
В моём мире всё наоборот: сначала мы получили знание о свойствах, и после этого получили возможность относить воду к одному или нескольким классам. DG>не обладает свойством быть выраженной — это нельзя построить алгоритм, который переводит эту программу в последовательность изменения состояния некоторого вычислителя?
Нет. Декларативность/императивность программы ничего не говорит о воможности трансформировать её в некоторую другую программу с другими свойствами.
Она является свойством самой программы в том виде, как она записана. DG>но для haskell-я и sql-я такой алгоритм есть, это означает что haskell и sql — императивные?
Вы не угадали.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>>В частности, приведённая программа не обладает свойством быть выраженной в терминах последовательного изменения состояния некоторого вычислителя.
DG>кстати, может ты хотел добавить про конечность алгоритма.
Нет, не хотел. DG>программу про кубы можно представить в виде бесконечного алгоритма последовательного перебора значений (x0, y0), (x0+1, y0), (x0+1, y0+1), (x0+2, y0+1) и т.д.
1. Что значит "бесконечный"? С точки зрения формулировки, этот алгоритм не более бесконечен, чем алгоритм поиска наибольшего общего делителя.
2. Если вы опираетесь на результат Эйлера в своём предположении о бесконечности алгоритма, то его можно представить в ещё более компактной форме:
start: goto start;
3. И, да, вы привели схему другой программы, которая, по косвенным признакам, является императивной. Это ничего не говорит об императивности исходной программы.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>Мутишь воду. Равная мощность языков по Тьюрингу не означает возможность автоматического перевода. Определение читал?
DG>если не требуется сохранить время выполнения, то означает.
Покажи мне автоматический перевод sql (без процедур) в регулярные выражения
DG>для перевода языка L1 в язык L2 без сохранения времени выполнения программы достаточно: DG>1. на языке L2 иметь компилируемый эмулятор языка L3 стековой машины (или, например, эмулятор asm x86),
А ты его автоматически получил?
G>>Более того императивную программу на haskell (завернутое в IO) не получится автоматически переписать в декларативную программу на haskell.
DG>можно, кстати, пример применения реальной программы на хаскеле, которая не использует монаду IO (или ее аналог)
Не понимаю, что ты подразумеваешь под аналогом монады, но вот тебе реальная программа, не использующая монаду IO:
ты говоришь, что конструкция foreach(x in items) в ФЯ есть функция, потому что кто-то такой ярлык наклеил, а такая же конструкция в C++ (for (var it = s.begin(); it != s.end(); ++it) — не есть функция, потому что в книжке про это не написано.
но свойства у этих двух конструкций одинаковые, а классификация должна делаться на основе свойств
монада — которая обеспечивает продолжение выполнение с произвольного места.
goto делает тоже самое
DG>>halt проще всего реализовывать через exception-ы DG>>http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception.html S>Если exception-ы принять за вариант результата функции, то ничего управляющего в них нет.
тоже самое можно принять и для C++, и для C#, что это просто такой хитрый результат вызова функции
DG>>это в логике существования. когда используется, что свойства чего-либо существуют без нашего знания о них, но проблема в том, что как тогда эти свойства на практике использовать, если мы о них не знаем? S>Не вижу проблемы. Свойства существуют независимо от нашего знания о них.
не научное (не конструктивное) определение — потому что нечего фальсифицировать
конструктивное определение — свойство существует независимо от нашего знания о нем, если свойство проявляется в независимости от нашего знания о нем
возьмем, следующий пример (и покажем, что существования свойства не достаточно для его проявления):
var items = (1, 3, 5, 7, 9);
var sortedItems = items.order-by();
здесь последовательность (1, 3, 5, 7, 9) имеет много свойств, и в частности имеет свойство: отсортированности по возрастанию.
Если мы (программист, компилятор, функция, исполнитель и т.д.) знаем, что эта последовательность отсортированная, то ее можно не сортировать (и код будет отрабатывать за O(1), если последовательность построена на этапе компиляции), если же про это свойство не знаем, то код будет работать за O(n*logn).
в тоже время код:
var x = 5 / i;
будет кидать исключение при делении на 0, в независимости от того, знает ли программист, компилятор, функция и т.д., что i может принимать значения 0, и что при делении на 0 кидается исключение.
здесь про то, что делить на на 0 нельзя, и что в данный момент i == 0 — знает самый "нижний" исполнитель: АЛУ в процессоре.
итого:
свойство упорядоченности в первом коде проявляется только, если мы о нем знаем — и для него нельзя считать, что оно существует в независимости от нашего знания
свойство "что деление на 0 прерывает последовательную работу функции" проявляется в независимости от нашего знания, и можно считать, что он существует без нашего знания о нем
DG>>>http://www.xoltar.org/old_site/2003//sep/09/haskellLoops.html S>>Я вижу там определение функции
DG>вот в этом и есть проблемы твоего подхода.
Не надо перевешивать на меня свои проблемы
DG>ты говоришь, что конструкция foreach(x in items) в ФЯ есть функция, потому что кто-то такой ярлык наклеил
Я такое не говорил. Я говорю что в хаскеле нет конструкции foreach. Какой ярлык — это я без понятия. К чему клеить-то, если такой конструкции в языке нет?
DG>, а такая же конструкция в C++ (for (var it = s.begin(); it != s.end(); ++it) — не есть функция, потому что в книжке про это не написано.
В книжке написано что это statement. Если разуешь глаза, то увидишь что он никак не обладает признаками функции.
DG>но свойства у этих двух конструкций одинаковые, а классификация должна делаться на основе свойств
Хреновая у тебя классификация, если она statement и функцию классифицирует одинаково.
DG>>>http://en.wikibooks.org/wiki/Haskell/Control_structures S>>Интересно, это для тебя тоже условный переход?
DG>это альтернатива. DG>условный переход есть частный случай альтернативы, и на большинстве задач условный переход по свойствам не отличим от альтернативы
Так и запишем, что алтьтернативу в определении ты не можешь отличить от инструкции на перевод управления по метке
DG>>>http://hackage.haskell.org/packages/archive/GotoT-transformers/1.0/doc/html/src/Control-Monad-Trans-Goto.html S>>Ты читал что там?
DG>монада — которая обеспечивает продолжение выполнение с произвольного места.
Ты знаешь что такое монада? Почитай определение на досуге. А потом подумай, как монада может обеспечить продолжение с произвольного места. Так вот, goto там это функция, которая берет монадное вычисление и возвращает монадное значение (со слов автора). DG>goto делает тоже самое
Тебя смутил ярлык "goto". Делает goto из C совершенно другое.
DG>>>halt проще всего реализовывать через exception-ы DG>>>http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception.html S>>Если exception-ы принять за вариант результата функции, то ничего управляющего в них нет.
DG>тоже самое можно принять и для C++, и для C#, что это просто такой хитрый результат вызова функции
С исключением можно работать, можно строить на нем логику, как и на результате. halt/exit таким свойством не обладает, значит не может быть ни рассмотрен, ни смоделирован в качестве результата функции.
Здравствуйте, gandjustas, Вы писали:
DG>>можно, кстати, пример применения реальной программы на хаскеле, которая не использует монаду IO (или ее аналог)
G>Нет, потому что main::IO()
Из этого не следует, что нельзя написать программу, не иcпользующую монаду IO. Потому, что монада — это не какой-то абстрактный тип IO, а тройка из конструктора типа и двух функций. Их можно и не использовать. Вот эта программа
использует (понятно, что putStr написана с использованием монады IO). Например, для написания консольных утилит, которые не ведут с пользователем диалога (не запрашивают данные по сети, не пишут файлы на диск и т.д.), а обрабатывают данные потоково, в качестве этапа конвейера — никакая монада IO не нужна:
main = interact $ чистая_функция
G>Отказаться от побочных эффектов нельзя. Вся суть любой программы в побочных эффектах.
Не любой, вот вышеупомянутая утилита командной строки, для одних и тех же данных, прочитанных из стандартного ввода записывающая одни и те же данные в стандартный вывод — никаких побочных эффектов не имеет. Но это, понятно, очень небольшое подмножество программ.
... << 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
DG>>>это в логике существования. когда используется, что свойства чего-либо существуют без нашего знания о них, но проблема в том, что как тогда эти свойства на практике использовать, если мы о них не знаем? S>>Не вижу проблемы. Свойства существуют независимо от нашего знания о них.
DG>не научное (не конструктивное) определение — потому что нечего фальсифицировать
DG>конструктивное определение — свойство существует независимо от нашего знания о нем, если свойство проявляется в независимости от нашего знания о нем
DG>возьмем, следующий пример (и покажем, что существования свойства не достаточно для его проявления): DG>
DG>здесь последовательность (1, 3, 5, 7, 9) имеет много свойств, и в частности имеет свойство: отсортированности по возрастанию.
Тут ты говоришь об одном свойстве — об отсортированности конкретной последовательности. DG>Если мы (программист, компилятор, функция, исполнитель и т.д.) знаем, что эта последовательность отсортированная, то ее можно не сортировать (и код будет отрабатывать за O(1), если последовательность построена на этапе компиляции), если же про это свойство не знаем, то код будет работать за O(n*logn).
Тут ты говоришь уже о другом свойстве — о возможности сэкономить за счет не сортировать если кто-то знает что оно уже отсортировано. Причем знание об отсортированности последовательности — это не свойство последовательности.
DG>в тоже время код: DG>
DG>var x = 5 / i;
DG>
DG>будет кидать исключение при делении на 0, в независимости от того, знает ли программист, компилятор, функция и т.д., что i может принимать значения 0, и что при делении на 0 кидается исключение. DG>здесь про то, что делить на на 0 нельзя, и что в данный момент i == 0 — знает самый "нижний" исполнитель: АЛУ в процессоре.
Тут ты вообще рассматриваешь свойство непонятно чего. Кода, АЛУ, программиста и т.п. Тем не менее, по поводу кода выше ты ошибся. Пруф:
var i = 0.0;
var x = 5 / i;// здесь твой код выше буква в букву.
Console.WriteLine(i == 0); // True
Console.WriteLine(x); // бесконечность
DG>итого: DG>свойство упорядоченности в первом коде проявляется только, если мы о нем знаем — и для него нельзя считать, что оно существует в независимости от нашего знания
Она обладает свойством упорядоченности независимо от твоего знания. Это легко проверить. Попроси кого-нибудь проверить упорядоченность и записать это на бумажку. Потом проверь сам. Сравни свое знание с бумажкой.
DG>свойство "что деление на 0 прерывает последовательную работу функции" проявляется в независимости от нашего знания, и можно считать, что он существует без нашего знания о нем
Я скажу больше. Все обладает своими свойствами без твоего знания об этом. Твои знания/незнания об этом могут влиять лишь на истинность твоих утверждений (а могут и не повлиять). Твой код будет работать верно или не верно вне зависимости от твоих знаний о нем, но в зависимости от других свойств, которыми обладают вещи, вне зависимости от твоих знаний об этом. И вне зависимости от твоих взглядов (конструктивистских или еще каких). Твои примеры это демонстрируют.
Здравствуйте, DarkGray, Вы писали:
DG>не научное (не конструктивное) определение — потому что нечего фальсифицировать
Хм. Мне лично вот кажется, что свойство воды занимать весь предоставленный ей объём можно легко фальсифицировать, опровергнув, таким образом, предположение о возможности классифицировать её как газ.
DG>возьмем, следующий пример (и покажем, что существования свойства не достаточно для его проявления): DG>
DG>здесь последовательность (1, 3, 5, 7, 9) имеет много свойств, и в частности имеет свойство: отсортированности по возрастанию. DG>Если мы (программист, компилятор, функция, исполнитель и т.д.) знаем, что эта последовательность отсортированная, то ее можно не сортировать (и код будет отрабатывать за O(1)
Отличный пример. DG>если же про это свойство не знаем, то код будет работать за O(n*logn).
Ну и откуда вы взяли это O(n*logn)? Вы, наверное, подразумеваете какую-то особенную реализацию внутри вашего order-by().
Если мы применим какой-нибудь реальный алгоритм, то окажется, что свойства последовательности будут проявляться независимо от нашего априорного знания о них.
Например, bubblesort обработает её за 4 сравнения и 0 перестановок — ровно столько нужно, чтобы убедиться, что имеет место свойство упорядоченности. А какую-то другую последовательность длины 5 он обработает за 20 сравнений и 20 перестановок.
Quicksort тоже существенно по-разному будет работать с разными последовательностями. Оценки, которыми вы столь смело оперируете, получены статистически — в предположении, что все возможные последовательности длины N равновероятны.
DG>в тоже время код: DG>
DG>var x = 5 / i;
DG>
DG>будет кидать исключение при делении на 0, в независимости от того, знает ли программист, компилятор, функция и т.д., что i может принимать значения 0, и что при делении на 0 кидается исключение.
Ещё один отличный пример. Если i не может принимать значения 0, то данный код никогда не будет бросать исключение.
DG>свойство упорядоченности в первом коде проявляется только, если мы о нем знаем — и для него нельзя считать, что оно существует в независимости от нашего знания
Как видим, вы опять не угадали.
А теперь, собственно, главный вопрос: при чём тут декларативность?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>В моём мире всё наоборот: сначала мы получили знание о свойствах, и после этого получили возможность относить воду к одному или нескольким классам.
во-первых: тогда получается тавтологичная классификация:
из наличия свойств A + B + C следует относимость к классу Z, а из относимости к классу Z только следуют свойства A, B и C.
во-вторых: ты в своих рассуждениях из утверждения: программа X — декларативная, делаешь вывод программа Z — не императивная. а такой вывод можно делать только если доказано, что свойства классов декларативная и императивная не пересекаются.
S>В моём мире всё наоборот: сначала мы получили знание о свойствах, и после этого получили возможность относить воду к одному или нескольким классам.
конструктивно это можно записать так: было проверено, что вода при нормальных условиях (примеси такие-то, температура такая-то, давление такое-то, сила тяжести такая-то, кол-во воды такое-то и т.д.) имеет такие-то и такие-то свойства и поэтому мы ее относим к классу жидкости. из отнесения к классу жидкости следует, что вода обладает при нормальных условиях такими-то, такими-то свойствами.
а дальше возникает вопрос: если нормальные условия поменяются (например, будут рассматриваться свойства воды при давлении 10тыс. атм), то какие свойства надо проверить, чтобы воду отнести к классу жидкости, и если мы ее отнесем к классу жидкости при таких условиях, то какие свойства из это следует?
с ЯП все тоже самое: 40 лет назад нормальные условия были другие — свойства декларативного ЯП и императивного ЯП не пересекались.
в частности, декларативную программу можно было выполнить множеством способом, а императивную — только одним.
для императивной программы был известен пошаговый алгоритм выполнения, для декларативной — нет.
и т.д.
и в те времена, если ЯП относили к классу декларативный, то из него следовали данные свойства, тоже самое для императивного.
прошло 40 лет и нормальные условия поменялись: развились алгоритмы, появились оптимизирующие исполнители и т.д.
и возникает вопрос: а что сегодня следует из того, если программа отнесена к тому или иному классу?
есть два утверждения — свойства всегда существуют в независимости от нашего знания, свойства не всегда существуют в независимости от нашего знания.
ты постулируешь первое из этих утверждений.
и я тебя спрашиваю: что тебя убедит, что первое утверждение не всегда верно? (это и есть возможность фальсификации)
DG>>не научное (не конструктивное) определение — потому что нечего фальсифицировать S>Хм. Мне лично вот кажется, что свойство воды занимать весь предоставленный ей объём можно легко фальсифицировать, опровергнув, таким образом, предположение о возможности классифицировать её как газ.
это ты о конкретном свойстве, а я тебя спрашиваю про возможность фальсификации общей формулировки "свойства существуют в независимости от нашего знания о них".
для появление фальсифицируемости — "существование свойства" вводят:
или через изменение поведения объекта: свойство X существует — если поведение объектов со свойством X отличается от поведения объектов без свойства X
или через изменение поведения окружения объекта: свойство X существует — если поведение окружения для объектов со свойством X отличается от поведения для объектов без свойства X
если под "существование свойства" понимается одна из таких формулировок, тогда уже можно говорит о возможности фальсификации утверждения "свойства всегда существуют в независимости от нашего знания".
пример попробую привести еще раз:
есть свойство S: последовательность упорядочена по возрастанию
есть другие свойства (которые базируются на свойстве S):
1. IEnumerable-последовательность про которую известно, что в ней все элементы отсортированы по возрастанию можно преобразовать за O(1) в IOrderedEnumerable
2. минимальный элемент для упорядоченной последовательности по возрастанию ищется за O(1)
и т.д.
при этом если код не знает, что последовательность обладает свойством упорядоченности по возрастанию, то код не может обеспечить время выполнения за O(1), и упорядоченные последовательности будут обрабатываться за время O(n) и больше (сравнимое с обработкой неупорядоченных последовательностей).
или другими словами: код ведет себя так, как будто свойства "упорядоченность по возрастанию" у последовательности не существует.
DG>>ты говоришь, что конструкция foreach(x in items) в ФЯ есть функция, потому что кто-то такой ярлык наклеил S>Я такое не говорил. Я говорю что в хаскеле нет конструкции foreach. Какой ярлык — это я без понятия. К чему клеить-то, если такой конструкции в языке нет?
DG>>, а такая же конструкция в C++ (for (var it = s.begin(); it != s.end(); ++it) — не есть функция, потому что в книжке про это не написано. S>В книжке написано что это statement. Если разуешь глаза, то увидишь что он никак не обладает признаками функции.
чтобы это увидеть необходимо эти признаки выписать.
как только ты их выпишешь, то даже самостоятельно увидишь, что для современных языков C#, Java, C++ — statement по этим признакам не отличается от функции (и уж тем более от монадной функции).
S>Ты знаешь что такое монада? Почитай определение на досуге. А потом подумай, как монада может обеспечить продолжение с произвольного места. Так вот, goto там это функция, которая берет монадное вычисление и возвращает монадное значение (со слов автора). DG>>goto делает тоже самое S>Тебя смутил ярлык "goto". Делает goto из C совершенно другое.
по какому признаку goto в C делает другое?
DG>>тоже самое можно принять и для C++, и для C#, что это просто такой хитрый результат вызова функции S>С исключением можно работать, можно строить на нем логику, как и на результате. halt/exit таким свойством не обладает, значит не может быть ни рассмотрен, ни смоделирован в качестве результата функции.
вот здесь ты конструктивен (в отличии от ситуаций выше), здесь ты уже приводишь реальный признак на основе которого отличаешь halt/exit от исключений.
и на это есть конструктивный ответ:
halt/exit является результатом функции, когда в качестве функции берется вся программа.
и логику можно построить и на halt/exit, но в качестве функций придется уже брать целые программы, что и делается, например, в unix way.
DG>>если не требуется сохранить время выполнения, то означает. S>Покажи мне автоматический перевод sql (без процедур) в регулярные выражения
дай реализацию машины тьюринга поверх регулярных выражений (раз ты утверждаешь, что регулярные выражения тьюринг-полные), а я тебе в ответ дам: транслятор sql в стековую машину, и транслятор стековой машины в машину тьюринга.
DG>>для перевода языка L1 в язык L2 без сохранения времени выполнения программы достаточно: DG>>1. на языке L2 иметь компилируемый эмулятор языка L3 стековой машины (или, например, эмулятор asm x86), S>А ты его автоматически получил?
конечно.
раз утверждается, что haskell тьюринг полный, то это означает, что для хаскеля есть транслятор, который умеет переводить машину тьюринга в хаскель.
а дальше берется готовый транслятор стековой машины для МТ: и в результате применения одного транслятора к результату другого транслятора — получаем, что поверх haskell-я выполняется стековая машина.
все это есть. но на практике это никому не надо, потому что оверхеды получаются дикие, и время выполнения растет лавинообразно после каждого преобразования.
соответственно, для практической применимости эквивалентности по тьюрингу мало. Для практической применимости добавляется требование "возможность преобразования с сохранением времени выполнения".
а обрабатывают данные потоково, в качестве этапа конвейера — никакая монада IO не нужна: K>
K>main = interact $ чистая_функция
K>
в данном случае программа — это "interact $ чистая функция", и эта конструкция использует монаду IO (а значит монада IO нужна) — как минимум, interact имеет тип: (String -> String) -> IO ()
если слова "использовать" и "нужна" заменить на слова "использовать в явном виде" и "учитывать особенности", то я согласен с исходным утверждением.
программа main = putStr "Hellow" тоже использует монаду IO, но не явно.
это доказывается тем, что если бы putStr "Hello" не использовал бы IO, то эту строку можно было бы вынести в функцию не имеющую "пометку" IO, а так сделать нельзя.
DG>>>ты говоришь, что конструкция foreach(x in items) в ФЯ есть функция, потому что кто-то такой ярлык наклеил S>>Я такое не говорил. Я говорю что в хаскеле нет конструкции foreach. Какой ярлык — это я без понятия. К чему клеить-то, если такой конструкции в языке нет?
DG>что значит нет? когда по ссылке она первой указана DG>>>>>http://www.xoltar.org/old_site/2003//sep/09/haskellLoops.html
Где ты там видишь конструкцию? Это функция чистой воды.
DG>>>, а такая же конструкция в C++ (for (var it = s.begin(); it != s.end(); ++it) — не есть функция, потому что в книжке про это не написано. S>>В книжке написано что это statement. Если разуешь глаза, то увидишь что он никак не обладает признаками функции.
DG>чтобы это увидеть необходимо эти признаки выписать. DG>как только ты их выпишешь, то даже самостоятельно увидишь, что для современных языков C#, Java, C++ — statement по этим признакам не отличается от функции (и уж тем более от монадной функции).
Вот тебе первый признак. Функция возвращает результат. Ни foreach, ни for этим признаком не обладают.
S>>Ты знаешь что такое монада? Почитай определение на досуге. А потом подумай, как монада может обеспечить продолжение с произвольного места. Так вот, goto там это функция, которая берет монадное вычисление и возвращает монадное значение (со слов автора). DG>>>goto делает тоже самое S>>Тебя смутил ярлык "goto". Делает goto из C совершенно другое.
DG>по какому признаку goto в C делает другое?
Он не возвращает результат. Это действительно тупой переход.
DG>>>тоже самое можно принять и для C++, и для C#, что это просто такой хитрый результат вызова функции S>>С исключением можно работать, можно строить на нем логику, как и на результате. halt/exit таким свойством не обладает, значит не может быть ни рассмотрен, ни смоделирован в качестве результата функции.
DG>вот здесь ты конструктивен (в отличии от ситуаций выше), здесь ты уже приводишь реальный признак на основе которого отличаешь halt/exit от исключений. DG>и на это есть конструктивный ответ: DG>halt/exit является результатом функции, когда в качестве функции берется вся программа.
Если тебе нужен в результате программы int — зачем тебе вся остальная программа? Сделай
int main { return 4; }
DG>и логику можно построить и на halt/exit, но в качестве функций придется уже брать целые программы, что и делается, например, в unix way.
А почему в unix way не заменяют программы на результат, не задумывался об этом?
Здравствуйте, DarkGray, Вы писали:
DG>в данном случае программа — это "interact $ чистая функция", и эта конструкция использует монаду IO (а значит монада IO нужна) — как минимум, interact имеет тип: (String -> String) -> IO ()
Вот именно. Как видите, никакой монады тут нет.
DG>если слова "использовать" и "нужна" заменить на слова "использовать в явном виде" и "учитывать особенности", то я согласен с исходным утверждением. DG>программа main = putStr "Hellow" тоже использует монаду IO, но не явно. DG>это доказывается тем, что если бы putStr "Hello" не использовал бы IO, то эту строку можно было бы вынести в функцию не имеющую "пометку" IO, а так сделать нельзя.
IO a и монада IO — разные вещи. IO a — тип для "действия". Монада — набор функций, которые позволяют комбинировать действия безопасным способом (с соблюдением порядка). В случае хаскеля, монада IO — это инстанс класса Monad. Комбинировать действия можно и другими инструментами. С помощью аппликативного функтора IO, стрелок и т.д.
В некоторый случаях, когда действие одно — можно вообще не комбинировать. Такие примеры приведены.
Если монады для комбинации действий не используются — значит не используются, а не "неявно используются". Неявно они используются, например, в случае синтаксического сахара вроде do-нотации, которая рассахаривается в комбинаторы класса Monad.
... << 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
Здравствуйте, DarkGray, Вы писали:
DG>>>если не требуется сохранить время выполнения, то означает. S>>Покажи мне автоматический перевод sql (без процедур) в регулярные выражения
DG>дай реализацию машины тьюринга поверх регулярных выражений (раз ты утверждаешь, что регулярные выражения тьюринг-полные), а я тебе в ответ дам: транслятор sql в стековую машину, и транслятор стековой машины в машину тьюринга.
А я такого не утверждал, перечитай на что отвечаешь.
DG>>>для перевода языка L1 в язык L2 без сохранения времени выполнения программы достаточно: DG>>>1. на языке L2 иметь компилируемый эмулятор языка L3 стековой машины (или, например, эмулятор asm x86), S>>А ты его автоматически получил?
DG>конечно. DG>раз утверждается, что haskell тьюринг полный, то это означает, что для хаскеля есть транслятор, который умеет переводить машину тьюринга в хаскель.
1. Вот ты его автоматически получил?
2. Ты обобщил в предыдущих ответах утверждение до вообще эквивалентных по тьюрингу, а не только для полных. Расхлебывай. DG>а дальше берется готовый транслятор стековой машины для МТ: и в результате применения одного транслятора к результату другого транслятора — получаем, что поверх haskell-я выполняется стековая машина.
DG>все это есть. но на практике это никому не надо, потому что оверхеды получаются дикие, и время выполнения растет лавинообразно после каждого преобразования.
DG>соответственно, для практической применимости эквивалентности по тьюрингу мало. Для практической применимости добавляется требование "возможность преобразования с сохранением времени выполнения".
К полноте по Тьюрингу это уже не имеет никакого отношения.
DG>>чтобы это увидеть необходимо эти признаки выписать. DG>>как только ты их выпишешь, то даже самостоятельно увидишь, что для современных языков C#, Java, C++ — statement по этим признакам не отличается от функции (и уж тем более от монадной функции). S>Вот тебе первый признак. Функция возвращает результат. Ни foreach, ни for этим признаком не обладают.
функция может вернуть пустой результат. монадическая функция может вернуть пустой результат + монаду
foreach и for в зависимости от условий может рассматриваться или как первый вариант, или как второй.
S>>>Ты знаешь что такое монада? Почитай определение на досуге. А потом подумай, как монада может обеспечить продолжение с произвольного места. Так вот, goto там это функция, которая берет монадное вычисление и возвращает монадное значение (со слов автора). DG>>>>goto делает тоже самое S>>>Тебя смутил ярлык "goto". Делает goto из C совершенно другое.
DG>>по какому признаку goto в C делает другое? S>Он не возвращает результат. Это действительно тупой переход.
можно считать, что goto возвращает результат блока на который произошел переход, и будет тоже самое, что делает goto в haskell.
или другими словами, код с goto можно автоматически нарезать на куски от метки до метки, и каждой такой кусок оформить как отдельную функцию (при этом локальные переменные исходного кода перейдут во входные/выходные параметры этих кусков), а дальше каждый goto заменить на вызов соответствующей функции.
и можно строго доказать, что код после такого преобразования будет эквивалентен исходному.
DG>>halt/exit является результатом функции, когда в качестве функции берется вся программа. S>Если тебе нужен в результате программы int — зачем тебе вся остальная программа? Сделай S>int main { return 4; }
halt/exit используются в основном для возврата результата для вырожденных данных (например, не соответствующих контракту).
полный тип спецификации batch-программы как функции: (string-cin, string) -> (int-result-code, string-cout, error-string-cerr) или (sequence-cin, string) -> (int-result-code, sequence-cout, error-sequence-cerr). возможны и более сложные варианты.
DG>>и логику можно построить и на halt/exit, но в качестве функций придется уже брать целые программы, что и делается, например, в unix way. S>А почему в unix way не заменяют программы на результат, не задумывался об этом?
как минимум, потому что такая замена имеет смысл при компиляции (и делать ее может лишь компилятор), а в unix way для связывания программ обычно используются скриптовые языки.
Здравствуйте, DarkGray, Вы писали:
S>>Вот тебе первый признак. Функция возвращает результат. Ни foreach, ни for этим признаком не обладают.
DG>функция может вернуть пустой результат. DG>монадическая функция может вернуть пустой результат + монаду
Что-что? Монаду? DG>foreach и for в зависимости от условий может рассматриваться или как первый вариант, или как второй.
Как первый не может, т.к. кроме возврата пустого результата для чего-то эти конструкции нужны. Второй — даже не понимаю, о чем речь. Загляни в определение монады.
DG>>>по какому признаку goto в C делает другое? S>>Он не возвращает результат. Это действительно тупой переход.
DG>можно считать, что goto возвращает результат блока на который произошел переход, и будет тоже самое, что делает goto в haskell.
Блок, на который произошел переход ничего возвращать не собирается. Это блок, а не выражение. DG>или другими словами, код с goto можно автоматически нарезать на куски от метки до метки, и каждой такой кусок оформить как отдельную функцию (при этом локальные переменные исходного кода перейдут во входные/выходные параметры этих кусков), а дальше каждый goto заменить на вызов соответствующей функции. DG>и можно строго доказать, что код после такого преобразования будет эквивалентен исходному.
Ты хочешь доказать, что код с goto можно преобразовать в функциональный? Пожалуйста. Но это будет уже другой код, а не тот, свойства которого ты пытаешься рассмотреть.
DG>>>halt/exit является результатом функции, когда в качестве функции берется вся программа. S>>Если тебе нужен в результате программы int — зачем тебе вся остальная программа? Сделай S>>int main { return 4; }
DG>halt/exit используются в основном для возврата результата для вырожденных данных (например, не соответствующих контракту). DG>полный тип спецификации batch-программы как функции: (string-cin, string) -> (int-result-code, string-cout, error-string-cerr) или (sequence-cin, string) -> (int-result-code, sequence-cout, error-sequence-cerr). возможны и более сложные варианты.
DG>>>и логику можно построить и на halt/exit, но в качестве функций придется уже брать целые программы, что и делается, например, в unix way. S>>А почему в unix way не заменяют программы на результат, не задумывался об этом?
DG>как минимум, потому что такая замена имеет смысл при компиляции (и делать ее может лишь компилятор), а в unix way для связывания программ обычно используются скриптовые языки.
Я толсто намекаю на то, что если бы от программы нужны были лишь ее коды, то не нужна бы была сама программа.
K>>IO a и монада IO — разные вещи.
DG>сами по себе IO, MayBe и т.д. как принято называть? монадический тип?
Это просто типы. Добавь к ним список хаскеля [] или IEnumerable из дотнета, есть куча других примеров. Nullable<T>, Lazy<T> и т.п.
Сами по себе они ничем не лучше и не хуже других. Но если рассмотреть их в совокупности с некоторыми функциями, то окажется что эти типы вместе с этими функциями обладают замечательными свойствами, позволяющие применять к ним некоторый прием.
Однако в Хаскеле, монада является еще и абстракцией, т.е. эти типы могут быть объявлены (а могут и нет) инстансом спецкласса. Само по себе к монаде это отношения имеет не больше, чем задание совместимых для Query Expressions методов в C#. Конечно, абстракция в Хаскеле позволяет делать с монадами более высокоуровневые вещи, чем можно себе позволить дотнет.
Здравствуйте, DarkGray, Вы писали:
S>>2. Ты обобщил в предыдущих ответах утверждение до вообще эквивалентных по тьюрингу, а не только для полных. Расхлебывай.
DG>утверждения "ЯП эквивалентен МТ" и "ЯП полный по тьюрингу" — это синонимы. из первое следует второе, а из второго первое.
DG>
если не брать время, то из эквивалентности языка C и языка haskell следует, что программу на языке C можно автоматически перевести на язык haskell, и соответственно любую императивную программу на языке C можно автоматически представить в декларативном виде.
Ты написал что автоматический перевод следует из эквивалентности. А я написал что не следует.
Здравствуйте, DarkGray, Вы писали:
DG>сами по себе IO, MayBe и т.д. как принято называть? монадический тип?
IO a и Maybe a — типы. IO и Maybe — конструкторы типов. Выражение "монадический тип" вообще довольно бессмысленно. Потому, что в типах не бывает ничего "монадического". Декларация типа никак его с монадами не связывает. А вот декларация инстанса класса Monad с типом связана. Поэтому логичнее говорить "монада Maybe", имея в виду набор операций определенных для типа Maybe, а не "монадический тип Maybe". Натуральные числа — это не сложение, и не "слагательные числа". Это множество, на котором определена операция "сложение натуральных чисел".
... << 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
K> Выражение "монадический тип" вообще довольно бессмысленно. Потому, что в типах не бывает ничего "монадического".
т.е. на вики написано не правильно, и необходимо использовать какой-то другой источник для понимания монад. какой?
Definition
A monad is a construction that, given an underlying type system, embeds a corresponding type system (called the monadic type system) into it (that is, each monadic type acts as the underlying type). This monadic type system preserves all significant aspects of the underlying type system, while adding features particular to the monad.
The usual formulation of a monad for programming is known as a Kleisli triple, and has the following components:
1.A type construction that defines, for every underlying type, how to obtain a corresponding monadic type. In Haskell's notation, the name of the monad represents the type constructor. If M is the name of the monad and t is a data type, then "M t" is the corresponding type in the monad.
2.A unit function that maps a value in an underlying type to a value in the corresponding monadic type. The result is the "simplest" value in the corresponding type that completely preserves the original value (simplicity being understood appropriately to the monad). In Haskell, this function is called return due to the way it is used in the do-notation described later. The unit function has the polymorphic type t→M t.
3.A binding operation of polymorphic type (M t)→(t→M u)→(M u), which Haskell represents by the infix operator >>=. Its first argument is a value in a monadic type, its second argument is a function that maps from the underlying type of the first argument to another monadic type, and its result is in that other monadic type. The binding operation can be understood as having four stages: 1.The monad-related structure on the first argument is "pierced" to expose any number of values in the underlying type t.
2.The given function is applied to all of those values to obtain values of type (M u).
3.The monad-related structure on those values is also pierced, exposing values of type u.
4.Finally, the monad-related structure is reassembled over all of the results, giving a single value of type (M u).
In object-oriented programming terms, the type construction would correspond to the declaration of the monadic type, the unit function takes the role of a constructor method, and the binding operation contains the logic necessary to execute its registered callbacks (the monadic functions).
S>>>2. Ты обобщил в предыдущих ответах утверждение до вообще эквивалентных по тьюрингу, а не только для полных. Расхлебывай.
DG>>утверждения "ЯП эквивалентен МТ" и "ЯП полный по тьюрингу" — это синонимы. из первое следует второе, а из второго первое.
DG>> S>
S>если не брать время, то из эквивалентности языка C и языка haskell следует, что программу на языке C можно автоматически перевести на язык haskell, и соответственно любую императивную программу на языке C можно автоматически представить в декларативном виде.
S>Ты написал что автоматический перевод следует из эквивалентности. А я написал что не следует.
ты выдернул цитату из контекста.
полный контекст:
G>>Мощность языков программирования по тьюрингу одинакова и они все выполняются на x86 процессорах. Так что фраза твоя ни о чем.
DG>эта эквивалентность не обещает, что алгоритм после преобразования останется вычислимым за заданное время.
G> А причем тут время? Мы про время еще ничего не говорили. Не надо лишние, для понимания сути, вещи включать.
DG> если не брать время, то из эквивалентности языка C и языка haskell следует, что программу на языке C можно автоматически перевести на язык haskell, и соответственно любую императивную программу на языке C можно автоматически представить в декларативном виде.
тут четко прослеживается, что под эквивалентностью языков понимается полнота по тьюрингу.
а из полноты по тьюрингу двух языков программирования L1 и L2 следует, что можно автоматически программу на языке L1 преобразовать в программу на языке L2 с помощью цепочки преобразований: L1 -> стековая машина -> МТ -> L2
это особенные типы для которых действует особые правила.
в частности, для монадического типа утверждается, что нельзя задать функцию вида monadic type -> type
можно лишь задавать функции вида:
m a -> m b
a -> m b
где m — монадический тип; a и b — обычный тип
S>>>Вот тебе первый признак. Функция возвращает результат. Ни foreach, ни for этим признаком не обладают.
DG>>функция может вернуть пустой результат. DG>>монадическая функция может вернуть пустой результат + монаду S>Что-что? Монаду?
пустой результат + монадический тип
DG>>foreach и for в зависимости от условий может рассматриваться или как первый вариант, или как второй. S>Как первый не может, т.к. кроме возврата пустого результата для чего-то эти конструкции нужны. Второй — даже не понимаю, о чем речь. Загляни в определение монады.
по первому согласен. с точки зрения haskell-я так не пройдет.
значит тогда второй вариант, for/foreach есть функция которая возвращает, например, монадический тип State (http://en.wikipedia.org/wiki/Monad_(functional_programming)#State_monads)
DG>>>>по какому признаку goto в C делает другое? S>>>Он не возвращает результат. Это действительно тупой переход.
DG>>можно считать, что goto возвращает результат блока на который произошел переход, и будет тоже самое, что делает goto в haskell. S>Блок, на который произошел переход ничего возвращать не собирается. Это блок, а не выражение.
каждый statement(если не брать пока ввод/вывод) императивной программы может рассматриваться как функция (vars) => (vars)
слева исходный statement, справа соответствующая функция на псевдокоде
var x = expr(); // vars => vars.concat((x, expr(vars)));
y = expr(); //vars => vars.where(pair => pair.var != y).concat((y, expr(vars)))if(expr())statement1 else statement2; // vars => expr(vars) ? statement1(vars) : statement2(vars)
;// vars => vars
{statement1; statement2; .. statementn;} // vars => statementn(..(statement2(statement1(vars))))while(expr) statement; // while(vars) => expr(vars) ? while(statement(vars)) : vars
для удобства vars можно завернуть в монаду state
DG>>или другими словами, код с goto можно автоматически нарезать на куски от метки до метки, и каждой такой кусок оформить как отдельную функцию (при этом локальные переменные исходного кода перейдут во входные/выходные параметры этих кусков), а дальше каждый goto заменить на вызов соответствующей функции. DG>>и можно строго доказать, что код после такого преобразования будет эквивалентен исходному. S>Ты хочешь доказать, что код с goto можно преобразовать в функциональный? Пожалуйста. Но это будет уже другой код, а не тот, свойства которого ты пытаешься рассмотреть.
это будет код, который делает то же самое, что и исходный. а значит это тот же самый код.
DG>>>>halt/exit является результатом функции, когда в качестве функции берется вся программа. S>>>Если тебе нужен в результате программы int — зачем тебе вся остальная программа? Сделай S>>>int main { return 4; }
DG>>halt/exit используются в основном для возврата результата для вырожденных данных (например, не соответствующих контракту). DG>>полный тип спецификации batch-программы как функции: (string-cin, string) -> (int-result-code, string-cout, error-string-cerr) или (sequence-cin, string) -> (int-result-code, sequence-cout, error-sequence-cerr). возможны и более сложные варианты.
DG>>>>и логику можно построить и на halt/exit, но в качестве функций придется уже брать целые программы, что и делается, например, в unix way. S>>>А почему в unix way не заменяют программы на результат, не задумывался об этом?
DG>>как минимум, потому что такая замена имеет смысл при компиляции (и делать ее может лишь компилятор), а в unix way для связывания программ обычно используются скриптовые языки. S>Я толсто намекаю на то, что если бы от программы нужны были лишь ее коды, то не нужна бы была сама программа.
то, что ты считаешь, что программы возвращают только код результата — это твое частное мнение, какое оно отношение имеет к реальному миру?
Здравствуйте, DarkGray, Вы писали: DG>и я тебя спрашиваю: что тебя убедит, что первое утверждение не всегда верно? (это и есть возможность фальсификации)
Независимая проверка. Берём двух "проверяющих", один проверяет наличие свойства и пишет на бумажке.
Второй пока ничего об этом свойстве не знает, и не знает, выполнялась ли вообще проверка первым.
Теперь он проверяет наличие свойства и обращается к первому — тот показывает бумажку.
Если во всех таких экспериментах результаты проверки первым и вторым совпадают — значит, свойства существуют независимо. Если не совпадают — значит это не свойства в нашем определении.
DG>для появление фальсифицируемости — "существование свойства" вводят: DG> или через изменение поведения объекта: свойство X существует — если поведение объектов со свойством X отличается от поведения объектов без свойства X DG> или через изменение поведения окружения объекта: свойство X существует — если поведение окружения для объектов со свойством X отличается от поведения для объектов без свойства X
Вам придётся сильно потрудиться в поисках объектов, поведение которых зависит от нашего знания о них.
DG>при этом если код не знает, что последовательность обладает свойством упорядоченности по возрастанию, то код не может обеспечить время выполнения за O(1), и упорядоченные последовательности будут обрабатываться за время O(n) и больше (сравнимое с обработкой неупорядоченных последовательностей). DG>или другими словами: код ведет себя так, как будто свойства "упорядоченность по возрастанию" у последовательности не существует.
Ваша ошибка в том, что вы путаете свойства последовательности и свойства кода. Последовательность вместе с её свойствами существует совершенно незаависимо от того, есть вообще какой-то код или нет. А вот разный код имеет разные свойства: один код умеет пользоваться априорной информацией о последовательности, другой — не умеет. Эти свойства кода также являются объективными, и существующими независимо от того, знаете вы про них или нет. И поведение кода, конечно же, будет зависеть от этих свойств.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>во-вторых: ты в своих рассуждениях из утверждения: программа X — декларативная, делаешь вывод программа Z — не императивная. а такой вывод можно делать только если доказано, что свойства классов декларативная и императивная не пересекаются.
Не обязательно. Мне достаточно ввести определения следующим образом:
1. Императивная программа — это та, которая сформулирована в терминах последовательного преобразования состояния некоторого вычислителя, причём стадий преобразования состояний — не менее чем три.
2. Декларативная программа — это любая программа, не являющаяся императивной.
DG>конструктивно это можно записать так: было проверено, что вода при нормальных условиях (примеси такие-то, температура такая-то, давление такое-то, сила тяжести такая-то, кол-во воды такое-то и т.д.) имеет такие-то и такие-то свойства и поэтому мы ее относим к классу жидкости. из отнесения к классу жидкости следует, что вода обладает при нормальных условиях такими-то, такими-то свойствами.
Я понимаю, чего вы хотите — каких-то нетривиальных выводов, предсказания одних свойств по другим свойствам.
DG>с ЯП все тоже самое: 40 лет назад нормальные условия были другие — свойства декларативного ЯП и императивного ЯП не пересекались. DG>в частности, декларативную программу можно было выполнить множеством способом, а императивную — только одним.
Это вы пытаетесь придумать своё определение декларативности, которое вам кажется более полезным, чем моё. Однако с вашим определением есть проблема — оно не вводит никакой классификации. Потому, что любую программу можно исполнить бесконечным количеством способов (то есть, есть несложный способ сконструировать произвольное количество эквивалентных ей императивных программ).
DG>для императивной программы был известен пошаговый алгоритм выполнения, для декларативной — нет. DG>прошло 40 лет и нормальные условия поменялись: развились алгоритмы, появились оптимизирующие исполнители и т.д.
С точки зрения внутреннего устройства, т.н. "оптимизирующий исполнитель" всегда устроен более-менее одинаковым образом: он сначала преобразует императивную программу (или её часть) в эквивалентную декларативную программу, а потом выбирает для этой декларативной программы некоторую другую императивную программу. Почитайте, к примеру, Аппеля про то, как устроен оптимизирующий компилятор.
Императивную программу "просто так" преобразовывать нельзя — она диктует поведение вычислителя в подробностях, не оставляющих места для манёвра. Вопрос о том, какие из этих подробностей являются существенными, а какие — нет, и решается при преобразовании в декларативную форму.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>и я тебя спрашиваю: что тебя убедит, что первое утверждение не всегда верно? (это и есть возможность фальсификации) S>Независимая проверка. Берём двух "проверяющих", один проверяет наличие свойства и пишет на бумажке. S>Второй пока ничего об этом свойстве не знает, и не знает, выполнялась ли вообще проверка первым. S>Теперь он проверяет наличие свойства и обращается к первому — тот показывает бумажку. S>Если во всех таких экспериментах результаты проверки первым и вторым совпадают — значит, свойства существуют независимо. Если не совпадают — значит это не свойства в нашем определении.
при этом обоим надо дать список свойств который надо проверить?
а откуда изначально этот список свойств берется?
S>1. Императивная программа — это та, которая сформулирована в терминах последовательного преобразования состояния некоторого вычислителя, причём стадий преобразования состояний — не менее чем три.
с помощью какого алгоритма можно выделить вычислитель из конкретной программы?
как, например, выделить вычислитель из программы на C#?
S>Я понимаю, чего вы хотите — каких-то нетривиальных выводов, предсказания одних свойств по другим свойствам.
если нет нетривиальных выводов, то нечего и фальсифицировать, а значит это не является научным знанием.
1. Императивная программа — это та, которая сформулирована в терминах последовательного преобразования состояния некоторого вычислителя, причём стадий преобразования состояний — не менее чем три.
2. Декларативная программа — это любая программа, не являющаяся императивной.
Здравствуйте, DarkGray, Вы писали:
DG>при этом обоим надо дать список свойств который надо проверить?
Конечно. DG>а откуда изначально этот список свойств берется?
Из третьего источника
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>с помощью какого алгоритма можно выделить вычислитель из конкретной программы? DG>как, например, выделить вычислитель из программы на C#?
Ну, лично я бы начал с чтения стандарта. Он очень внятно описывает семантику программы C#, ссылаясь на семантику виртуальной машины дотнета.
Эта виртуальная машина и есть тот вычислитель, в терминах которого описана программа на С#.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>что здесь можно фальсифицировать и каким образом?
Здесь, я думаю, фальсифицировать ничего нельзя. Наверное, это проблема.
Но аналогичная проблема каким-то образом была решена, скажем, для определений простых и составных чисел.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>Ты написал что автоматический перевод следует из эквивалентности. А я написал что не следует.
DG>ты выдернул цитату из контекста. DG>полный контекст: DG>
G>>>Мощность языков программирования по тьюрингу одинакова и они все выполняются на x86 процессорах. Так что фраза твоя ни о чем.
DG>>эта эквивалентность не обещает, что алгоритм после преобразования останется вычислимым за заданное время.
G>> А причем тут время? Мы про время еще ничего не говорили. Не надо лишние, для понимания сути, вещи включать.
DG>> если не брать время, то из эквивалентности языка C и языка haskell следует, что программу на языке C можно автоматически перевести на язык haskell, и соответственно любую императивную программу на языке C можно автоматически представить в декларативном виде.
DG>тут четко прослеживается, что под эквивалентностью языков понимается полнота по тьюрингу. DG>а из полноты по тьюрингу двух языков программирования L1 и L2 следует, что можно автоматически программу на языке L1 преобразовать в программу на языке L2 с помощью цепочки преобразований: L1 -> стековая машина -> МТ -> L2
Ты о том, что отношение эквивалентности построено на полноте по Тьюрингу? Это подразумевает как минимум два класса эквивалентности — полных и неполных по Тьюрингу программ. Из того что две программы эквивалентны — не следует возможность автоматической конвертации. Что бы следовала такая возможность достаточно будет полноты обоих по Тьюрингу, т.е. принадлежности к одному классу эквивалентности на отношении полноты, и полных притом.
DG>с чем ты не согласен?
Я не согласен со строгостью твоих утвреждений.
S>>Это просто типы.
DG>это особенные типы для которых действует особые правила. DG>в частности, для монадического типа утверждается, что нельзя задать функцию вида monadic type -> type
У тебя слишком богатая фантазия. Выдумываешь на ровном месте. Вот, смотри, можно:
head (x:xs) = x
head [] = error"head{PreludeList}: head []"
DG>можно лишь задавать функции вида: DG>m a -> m b DG>a -> m b DG>где m — монадический тип; a и b — обычный тип
Удивлю тебя, можно еще задавать функции вида
Здравствуйте, DarkGray, Вы писали:
S>>>>Вот тебе первый признак. Функция возвращает результат. Ни foreach, ни for этим признаком не обладают.
DG>>>функция может вернуть пустой результат. DG>>>монадическая функция может вернуть пустой результат + монаду S>>Что-что? Монаду?
DG>пустой результат + монадический тип
Уже потерял нить разговора, лень восстанавливать. Но хорошо уже то, что функция не возвращает монаду.
DG>>>foreach и for в зависимости от условий может рассматриваться или как первый вариант, или как второй. S>>Как первый не может, т.к. кроме возврата пустого результата для чего-то эти конструкции нужны. Второй — даже не понимаю, о чем речь. Загляни в определение монады.
DG>по первому согласен. с точки зрения haskell-я так не пройдет. DG>значит тогда второй вариант, for/foreach есть функция которая возвращает, например, монадический тип State (http://en.wikipedia.org/wiki/Monad_(functional_programming)#State_monads)
то есть на C ты можешь написать return for(...)?
S>>Блок, на который произошел переход ничего возвращать не собирается. Это блок, а не выражение.
DG>каждый statement(если не брать пока ввод/вывод) императивной программы может рассматриваться как функция (vars) => (vars) DG>слева исходный statement, справа соответствующая функция на псевдокоде DG>
DG>var x = expr(); // vars => vars.concat((x, expr(vars)));
DG>y = expr(); //vars => vars.where(pair => pair.var != y).concat((y, expr(vars)))
DG>if(expr())statement1 else statement2; // vars => expr(vars) ? statement1(vars) : statement2(vars)
DG>;// vars => vars
DG>{statement1; statement2; .. statementn;} // vars => statementn(..(statement2(statement1(vars))))
DG>while(expr) statement; // while(vars) => expr(vars) ? while(statement(vars)) : vars
DG>
Не осилил
DG>для удобства vars можно завернуть в монаду state
Когда завернешь, получишь совсем другую программу.
DG>>>и можно строго доказать, что код после такого преобразования будет эквивалентен исходному. S>>Ты хочешь доказать, что код с goto можно преобразовать в функциональный? Пожалуйста. Но это будет уже другой код, а не тот, свойства которого ты пытаешься рассмотреть.
DG>это будет код, который делает то же самое, что и исходный. а значит это тот же самый код.
По твоей логике все коды, которые вычисляют факториал, на самом деле являются одним и тем же самым кодом?
S>>Я толсто намекаю на то, что если бы от программы нужны были лишь ее коды, то не нужна бы была сама программа.
DG>то, что ты считаешь, что программы возвращают только код результата — это твое частное мнение, какое оно отношение имеет к реальному миру?
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, DarkGray, Вы писали: DG>>и я тебя спрашиваю: что тебя убедит, что первое утверждение не всегда верно? (это и есть возможность фальсификации) S>Независимая проверка. Берём двух "проверяющих", один проверяет наличие свойства и пишет на бумажке. S>Второй пока ничего об этом свойстве не знает, и не знает, выполнялась ли вообще проверка первым. S>Теперь он проверяет наличие свойства и обращается к первому — тот показывает бумажку. S>Если во всех таких экспериментах результаты проверки первым и вторым совпадают — значит, свойства существуют независимо. Если не совпадают — значит это не свойства в нашем определении.
По такому эксперименту невозможно делать выводы о том что свойства существуют независимо. Т.е. если результаты будут совпадать, то это ничего не доказывает, а только дает повод к предположению о том что есть тенденция.
Но я таки склонен полагать что свойства от знаний не зависят, т.е. шутка Шредингера для меня смешная (безотносительно судьбы кота).
DG>>при этом обоим надо дать список свойств который надо проверить? S>Конечно. DG>>а откуда изначально этот список свойств берется? S>Из третьего источника
и соответственно, существуют только те свойства, которые есть в этом списке?
S>Но аналогичная проблема каким-то образом была решена, скажем, для определений простых и составных чисел.
она решена тем способом, что это классификация не тавтологична, и если определено, что число простое или составное из этого можно вывести ряд других свойств.
DG>>и я тебя спрашиваю: что тебя убедит, что первое утверждение не всегда верно? (это и есть возможность фальсификации) S>Независимая проверка. Берём двух "проверяющих", один проверяет наличие свойства и пишет на бумажке.
есть свойство:
a^n = b^n + c^n не имеет решения в натуральных чисел, для n больше 2
вот если взять тебя и samius-а запереть в пустых комнатах и попросить проверить это свойство, то что вы ответите?
S>Ты о том, что отношение эквивалентности построено на полноте по Тьюрингу? Это подразумевает как минимум два класса эквивалентности — полных и неполных по Тьюрингу программ.
да, есть класс неполных по тьюрингу языков — но об их эквивалентности никто ничего и не утверждает
т.е. утверждается только, что языки A и B эквиваленты, если на A можно реализовать MT с бесконечной лентой и на B можно реализовать MT с бесконечной лентной
Здравствуйте, DarkGray, Вы писали:
S>>Ты о том, что отношение эквивалентности построено на полноте по Тьюрингу? Это подразумевает как минимум два класса эквивалентности — полных и неполных по Тьюрингу программ.
DG>да, есть класс неполных по тьюрингу языков — но об их эквивалентности никто ничего и не утверждает
Еще раз. Ты вывел автоконвертацию из эквивалентности.
DG>т.е. утверждается только, что языки A и B эквиваленты, если на A можно реализовать MT с бесконечной лентой и на B можно реализовать MT с бесконечной лентной
Языки которые не позволяют релизовать МТ с бесконечной лентой тоже эквивалентны по такому отношению эквивалентности.
Здравствуйте, DarkGray, Вы писали:
K>> Выражение "монадический тип" вообще довольно бессмысленно. Потому, что в типах не бывает ничего "монадического". DG>т.е. на вики написано не правильно
Называть переменную m в Monad m => m a монадическим типом как раз вполне логично, во-первых потому, что на нем определены монадические операции, а во-вторых, ничего другого мы о нем, в общем-то и не знаем. В типе data Maybe a = Just a | Nothing самом по себе, без instance Monad Maybe ничего "монадического" нет.
... << 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
Здравствуйте, DarkGray, Вы писали:
DG>это особенные типы
Понятно, что для возможности определния инстанса Monad тип должен обладать некоторыми свойствами, например быть "unconstrained", конструктор типа должен иметь кайнд * -> *. Отчасти это особенности или недостатки системы типов хаскеля, которые частично преодолены в новой версии, отчасти фундаментальные свойства монад. Но ни одно из этих требований само по себе и все они вместе не делают тип монадическим. А делают определенные на нем операции. Какой смысл говорить об использовании монад, если в программе нет ни одного выражения с типом, ограниченным констрейнтом Monad. Это все равно, что утверждать об использовании сложения на основании присутствия в сигнатуре типа int.
DG>для которых действует особые правила.
Правила действуют для определенных над этим типом операций. Правило такое: тройка (m, >=>, return) — моноид.
DG>в частности, для монадического типа утверждается, что нельзя задать функцию вида monadic type -> type
Получить комбинацией монадических функций функцию с сигнатурой Monad m => m a -> a нельзя. Это и обеспечивает безопасность комбинации действий. Написать функцию для конкретного типа Maybe a -> a или [a] -> a не проблема. Тип IO a — абстрактный. Это означает, что его конструктор не экспортируется и его (упрощенно) нельзя (де)конструировать за пределами модуля, в котором он объявлен. Это другой аспект обеспечения безопасности комбинирования действий и к монадам отношения не имеет.
... << 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
Здравствуйте, DarkGray, Вы писали:
DG>вот если взять тебя и samius-а запереть в пустых комнатах и попросить проверить это свойство, то что вы ответите?
Ну, если нам предоставить неограниченное время, то я склонен полагать, что мы ответим то же, что и Уайлс.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>и соответственно, существуют только те свойства, которые есть в этом списке?
С чего бы это? Нет, существуют все свойства, которые только есть. Это в вашей модели мира свойства внезапно появляются в момент проверки. В моей — свойства существуют объективно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, samius, Вы писали: S>По такому эксперименту невозможно делать выводы о том что свойства существуют независимо. Т.е. если результаты будут совпадать, то это ничего не доказывает, а только дает повод к предположению о том что есть тенденция.
Это понятно. Тем не менее, у нас есть некое предположение, а также способ его опровержения. Пока опровержение не получено, мы можем считать предположение верным. S>Но я таки склонен полагать что свойства от знаний не зависят, т.е. шутка Шредингера для меня смешная (безотносительно судьбы кота).
С котом Шредингера есть некоторая тонкость: гуманитарии склонны неверно трактовать понятие "наблюдатель" в квантовой механике. Из-за этого непонимания рождается масса "парадоксов".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>вот если взять тебя и samius-а запереть в пустых комнатах и попросить проверить это свойство, то что вы ответите? S>Ну, если нам предоставить неограниченное время, то я склонен полагать, что мы ответим то же, что и Уайлс.
проблема в том, что в реальности нет бесконечнего времени. и что опереться и использовать можно только те свойства, которые мы наблюдаем (и заморочка в том, что большинство сложных свойств не наблюдается напрямую: так называемое смотрим, но не видим).
можно долго спорить на тему: может ли быть существование субъективным или не может (и все упирается в то, как именно трактуется слово существование: существование — это то, что есть в мире (с точки зрения абсолютного наблюдателя), существование — это то, что есть у нас (точка зрения — локальный наблюдатель))
предлагаю перейти сразу к конструктиву:
ты согласен с тем, что человек (или автомат со сложным управлением или аналог) может опираться и использовать только те свойства, о которых знает и/или наблюдает?
также отмечу, что в ряде случаев, даже возможности наблюдения могут зависеть от знания (например, отличить сложное неслучайное поведение от сложного случайного поведения можно только имея знания стат. аппарата)
предлагаю ввести термин существование с точки зрения локального наблюдателя (л-сущестование) и тогда появлется ряд формулировок:
знание — подвид информации, используемой для трактовки какой-либо информации
знанение можно поделить на два: уже известное и еще неизвестное знание на текущий момент
л-существует только то, о чем есть известное знание.
наблюдение — это есть переход неизвестного знания в известное
л-существование чего-либо делится на три категории(класса): что-либо л-существует; что-либо л-не существует; что-либо л-неопределено, то ли существует, то ли нет. л-не существует — очень маленький класс, т.к. при неполном знании есть мало способов доказать, что чего-либо не существует.
лн-несущестование — (л-несуществование + л-неопределенное существование). л-неопределенное сущестование по умолчанию трактуется как несуществование (бритва оккамы), для резкого уменьшения рассматриваемых вариантов.
лр-наблюдатель — локальный реальный наблюдатель, имеющий ограниченные возможности по хранению, восприятию и обработке информации
л-сущестование может отличатся для разных лр-наблюдателей в том числе и находящихся в одной точке пространства-времени (из-за того, что они могут иметь разных набор известного знания, и разные возможности по хранению, восприятию и обработке информации)
Здравствуйте, DarkGray, Вы писали:
DG>с этими формулировками согласен?
Давайте лучше вернёмся к вашим смешным примерам про отсортированность последовательности, и к тому, что информация про свойства != наличию свойств.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>с этими формулировками согласен? S>Давайте лучше вернёмся к вашим смешным примерам про отсортированность последовательности, и к тому, что информация про свойства != наличию свойств.
к чему там возвращаться? если я согласен, что твоя позиция верная, если верность оценивать с точки зрения абсолютного наблюдателя с бесконечными временными, вычислительными и энергетическими и т.д. ресурсами.
я лишь сомневаюсь, что попытки исходить с точки зрения абсолютного наблюдателя ведут к чему-то полезному в сложных задачах.
и вот здесь уже могут быть разногласия меня с тобой, если ты считаешь иначе (твое мнение по этому вопросу в треде еще не было).
зы
в частности, попытка раз и навсегда зафиксировать термины — тоже подразумевает, что мир рассматривается через призму абсолютного наблюдателя с бесконечными ресурсами.
DG>>т.е. утверждается только, что языки A и B эквиваленты, если на A можно реализовать MT с бесконечной лентой и на B можно реализовать MT с бесконечной лентной S>Языки которые не позволяют релизовать МТ с бесконечной лентой тоже эквивалентны по такому отношению эквивалентности.
приведи последовательность логический утверждений, которая это показывает, тем более ты математик — для тебя это должно быть раз плюнуть.
мое утверждение на языке логики:
верно следующее утверждение: "A можно реализовать на MT" and "B можно реализовать на MT" -> "A и B эквивалентны".
стрелка — это оператор импликации
DG>>>т.е. утверждается только, что языки A и B эквиваленты, если на A можно реализовать MT с бесконечной лентой и на B можно реализовать MT с бесконечной лентной S>>Языки которые не позволяют релизовать МТ с бесконечной лентой тоже эквивалентны по такому отношению эквивалентности.
DG>приведи последовательность логический утверждений, которая это показывает, тем более ты математик — для тебя это должно быть раз плюнуть. DG>мое утверждение на языке логики: DG>верно следующее утверждение: "A можно реализовать на MT" and "B можно реализовать на MT" -> "A и B эквивалентны". DG>стрелка — это оператор импликации
Обозначим твое утвреждение (*)
Вообще-то речь сначала была о Тьюринг-полных языках, потом о тех, на которых можно реализовать МТ с бесконечной лентой, а теперь о тех, что "можно реализовать на МТ". Ты такой резкий на смену тем! Хорошо, я тоже перелючусь на новое свойство.
На самом деле приводить выкладки не так просто, зная твою склонность трактовать определения. Мне пришлось сделать несколько предположений.
Допускаю что ты под эквивалентностью подразумеваешь отношение эквивалентности, а не какую-то свою эквивалентность. Если какую-то свою, то все другие рассуждения неверны.
Сначала утверждение о том, что твое утверждение это не определение эквивалентности, а лишь его свойство. Что бы оно являлось определением, нужно что бы отношение было определено на любых элементах множества (всех языков), а не на подмножестве.
Теперь, раз ты не определил конкретное отношение, я вправе делать допущение о том что твое отношение эквивалентности построено на свойстве языка иметь возможность быть реализованным на МТ. Это наиболее очевидное предположение, другие не столь очевидны. Но если ты таки формализуешь двоичное отношение, на котором строишь эквивалентность, то я рассмотрю возможность пересмотреть свои выводы.
Кстати, для такого отношения твое утверждение (*) истинно.
Это отношение делит множество всех языков на 2 класса эквивалентности.
1 — класс языков, для которых реализация на МТ возможна
2 — класс языков, для которых реализация на МТ невозможна.
В каждом классе эквивалентности все элементы эквивалентны, потому все элементы класса 2 эквивалентны с точки зрения возможности быть реализованным на МТ.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали: S>>По такому эксперименту невозможно делать выводы о том что свойства существуют независимо. Т.е. если результаты будут совпадать, то это ничего не доказывает, а только дает повод к предположению о том что есть тенденция. S>Это понятно. Тем не менее, у нас есть некое предположение, а также способ его опровержения. Пока опровержение не получено, мы можем считать предположение верным.
Да, считать совершенно правильно выделено курсивом. В тот момент, когда опровежение будет найдено, свойства не изменятся, но считать придется уже по-другому.
S>>Но я таки склонен полагать что свойства от знаний не зависят, т.е. шутка Шредингера для меня смешная (безотносительно судьбы кота). S>С котом Шредингера есть некоторая тонкость: гуманитарии склонны неверно трактовать понятие "наблюдатель" в квантовой механике. Из-за этого непонимания рождается масса "парадоксов".
Шредингер ведь не был гуманитарием
S>Допускаю что ты под эквивалентностью подразумеваешь отношение эквивалентности, а не какую-то свою эквивалентность. Если какую-то свою, то все другие рассуждения неверны.
языки A и B эквиваленты — если алгоритм записанный на языке А можно записать на языке B (и наоборот)
S>>Допускаю что ты под эквивалентностью подразумеваешь отношение эквивалентности, а не какую-то свою эквивалентность. Если какую-то свою, то все другие рассуждения неверны.
DG>языки A и B эквиваленты — если алгоритм записанный на языке А можно записать на языке B (и наоборот)
Скользкое утверждение. Что значит "можно записать"?
Например такой алгоритм на C#:
from x in xs
from y in ys
let z = x*y
where z % 2 == 0
select z;
На языке java не запишешь, там нету ни Linq, ни extension медотов.
Хотя очевидно что сделать программу, дающую тот же результат, проще простого.
DG>>языки A и B эквиваленты — если алгоритм записанный на языке А можно записать на языке B (и наоборот) S>Совсем другая эквивалентность, чем та, которую ты определял через возможность реализовать МТ (и на МТ). Для того что бы языки были эквивалентны по такой эквивалентности, не нужно что бы даже один из них имел отношение к МТ.
эквивалентность по тьюрингу — это подмножество этой эквивалентности, образующие один класс языков из этой эквивалентности.
и соответственно, доказано, что достаточно показать, что на языке A можно реализовать single-tape MT, и этот язык будет эквивалентен всем другим языкам с таким же свойством (верно и обратное, если удалось показать, что для языка single-tape MT не строится, то он в этот класс не входит)
DG>>>языки A и B эквиваленты — если алгоритм записанный на языке А можно записать на языке B (и наоборот) S>>Совсем другая эквивалентность, чем та, которую ты определял через возможность реализовать МТ (и на МТ). Для того что бы языки были эквивалентны по такой эквивалентности, не нужно что бы даже один из них имел отношение к МТ.
DG>эквивалентность по тьюрингу — это подмножество этой эквивалентности, образующие один класс языков из этой эквивалентности.
Что такое подмножество отношения эквивалентности? DG>и соответственно, доказано, что достаточно показать, что на языке A можно реализовать single-tape MT, и этот язык будет эквивалентен всем другим языкам с таким же свойством (верно и обратное, если удалось показать, что для языка single-tape MT не строится, то он в этот класс не входит)
Я тебе о другом. Что языки, на которых single-tape MT не строится, являются эквивалентными в отношении, построенном на свойстве построимости МТ.
G>>Скользкое утверждение. Что значит "можно записать"?
DG>существует алгоритм, который автоматически преобразует запись языка A в язык B. DG>при этом на время выполнения полученного кода наплевать.
G>>Например такой алгоритм на C#:
G>>
G>>from x in xs
G>>from y in ys
G>>let z = x*y
G>>where z % 2 == 0
G>>select z;
G>>
G>>На языке java не запишешь, там нету ни Linq, ни extension медотов.
DG>эта штука автоматически преобразуется к такой записи
DG>
DG>var list = new List<object>();
DG>foreach (var x in xs)
DG>foreach (var y in ys)
DG>{
DG> var z = x * y;
DG> if (z % 2 == 0)
DG> result.Add(z);
DG>}
DG>return list;
DG>
DG>как это преобразовать в Java-у надо показывать?
Ты ведь понимаешь что это не эквивалентный код. Надеюсь тебе не надо объяснять разницу между IEnumerable и List.
С другой стороны ни одним автоматическим преобразователем код на Linq как выше из java не получишь.
G>Ты ведь понимаешь что это не эквивалентный код. Надеюсь тебе не надо объяснять разницу между IEnumerable и List.
с точки зрения получения результата они эквиваленты, и тот и другой код дадут один и тот же результат (а аппеляция к тьюрингу только это и обещает)
они могут быть не эквиваленты только с точки зрения времени выполнения. о чем я сразу и говорил.
G>С другой стороны ни одним автоматическим преобразователем код на Linq как выше из java не получишь.
такой не получишь, но можно получить страшный код вида: поверх linq реализован автомат для обработки списков, а исходный код преобразован в этот автомат — результат выполнения будет тот же самый, а вот время выполнения уплывет.
зы
если вернуться к исходным утверждениям:
DG> у3. если для программы известен алгоритм, позволяющий выполнить ее с помощью процессора x86(за предсказуемое время с потреблением предсказуемого кол-ва ресурсов), то с большей вероятностью, она принадлежит к классу императивных программ.
то это как раз то, что ты хочешь, чтобы программа после преобразования не просто выдала такой же результат, как и исходная, но и сохранилось сравнимое время выполнения
DG>>>>языки A и B эквиваленты — если алгоритм записанный на языке А можно записать на языке B (и наоборот) S>>>Совсем другая эквивалентность, чем та, которую ты определял через возможность реализовать МТ (и на МТ). Для того что бы языки были эквивалентны по такой эквивалентности, не нужно что бы даже один из них имел отношение к МТ.
DG>>эквивалентность по тьюрингу — это подмножество этой эквивалентности, образующие один класс языков из этой эквивалентности. S>Что такое подмножество отношения эквивалентности?
есть множество всех языков и на нем задано отношение эквивалентности (если из A можно построить B, а из B -> A, то они эквивалентны)
это даем нам множество троек (язык Li, язык Lj, Eij), где Eij — это да/нет, эквивалентны или нет языки Li,Lj
которую можно построить из множества троек (язык Li, язык Lj, ->ij), где "->ij" — да/нет, можно построить или нет
тьринг рассмотрел только подмножество этого множества (Li, single-tape MT, ->ij:true) и показал, что из этого следует (Li, single-tape MT, Eij:true) и соответственно (Li, Lj, Eij:true), для Li, Lj таких, что на них можно построить single-tape MT
DG>>и соответственно, доказано, что достаточно показать, что на языке A можно реализовать single-tape MT, и этот язык будет эквивалентен всем другим языкам с таким же свойством (верно и обратное, если удалось показать, что для языка single-tape MT не строится, то он в этот класс не входит)
S>Я тебе о другом. Что языки, на которых single-tape MT не строится, являются эквивалентными в отношении, построенном на свойстве построимости МТ.
есть такое, только это тривиальный вывод, который ни к чему полезному не ведет.
Здравствуйте, DarkGray, Вы писали:
DG>>>>>языки A и B эквиваленты — если алгоритм записанный на языке А можно записать на языке B (и наоборот) S>>>>Совсем другая эквивалентность, чем та, которую ты определял через возможность реализовать МТ (и на МТ). Для того что бы языки были эквивалентны по такой эквивалентности, не нужно что бы даже один из них имел отношение к МТ.
DG>>>эквивалентность по тьюрингу — это подмножество этой эквивалентности, образующие один класс языков из этой эквивалентности. S>>Что такое подмножество отношения эквивалентности?
DG>есть множество всех языков и на нем задано отношение эквивалентности (если из A можно построить B, а из B -> A, то они эквивалентны)
Я, ранее:
Вообще-то речь сначала была о Тьюринг-полных языках, потом о тех, на которых можно реализовать МТ с бесконечной лентой, а теперь о тех, что "можно реализовать на МТ". Ты такой резкий на смену тем! Хорошо, я тоже перелючусь на новое свойство.
Теперь ты переключился на еще одно отношение эквивалентности, которое без МТ. С тобой так занятно! Пока я пытаюсь объяснить тебе, о чем ты сделал утверждение, ты уже несколько раз сменил тему.
DG>это даем нам множество троек (язык Li, язык Lj, Eij), где Eij — это да/нет, эквивалентны или нет языки Li,Lj DG>которую можно построить из множества троек (язык Li, язык Lj, ->ij), где "->ij" — да/нет, можно построить или нет DG>тьринг рассмотрел только подмножество этого множества (Li, single-tape MT, ->ij:true) и показал, что из этого следует (Li, single-tape MT, Eij:true) и соответственно (Li, Lj, Eij:true), для Li, Lj таких, что на них можно построить single-tape MT
Это твой ответ на вопрос "что такое подмножество отношения эквивалентности?"?
DG>>>и соответственно, доказано, что достаточно показать, что на языке A можно реализовать single-tape MT, и этот язык будет эквивалентен всем другим языкам с таким же свойством (верно и обратное, если удалось показать, что для языка single-tape MT не строится, то он в этот класс не входит)
S>>Я тебе о другом. Что языки, на которых single-tape MT не строится, являются эквивалентными в отношении, построенном на свойстве построимости МТ.
DG>есть такое, только это тривиальный вывод, который ни к чему полезному не ведет.
Так вот, ты сделал утверждение, которое говорит о возможности автоконвертации и для таких языков тоже.
DG>>с помощью какого алгоритма можно выделить вычислитель из конкретной программы? DG>>как, например, выделить вычислитель из программы на C#? S>Ну, лично я бы начал с чтения стандарта. Он очень внятно описывает семантику программы C#, ссылаясь на семантику виртуальной машины дотнета. S>Эта виртуальная машина и есть тот вычислитель, в терминах которого описана программа на С#.
если хочется подходить с позиции абсолютного наблюдателя, то вычислитель из C# необходимо восстановить имея листинги программ на C# и результаты выполнения этих программ.
иначе ты подходишь с позиции лр-наблюдателя: известно, что в C# есть вычислитель, потому что есть доступ к знанию в котором написано, что в C# есть вычислитель, а в SQL нет вычислителя, потому что нет доступа к знанию, в котором написано, что в SQL есть вычислитель
Здравствуйте, DarkGray, Вы писали:
DG>если хочется подходить с позиции абсолютного наблюдателя, то вычислитель из C# необходимо восстановить имея листинги программ на C# и результаты выполнения этих программ. DG>иначе ты подходишь с позиции лр-наблюдателя: известно, что в C# есть вычислитель, потому что есть доступ к знанию в котором написано, что в C# есть вычислитель, а в SQL нет вычислителя, потому что нет доступа к знанию, в котором написано, что в SQL есть вычислитель
Простите, это чушь.
Я подхожу с очень простой позиции: семантика программы определяется её текстом и спецификацией языка. Спецификация языка либо оперирует некоторым вычислителем, либо нет.
Определять императивность или декларативность с помощью угадывания — увольте.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Я подхожу с очень простой позиции: семантика программы определяется её текстом и спецификацией языка.
из всей спецификации важна только часть, которая специфицирует результат программы.
возьмем запись "1 + 2 * 3", ее можно специфицировать через вычислитель (стековую машину), можно через правила математики, можно еще стопятнадцатью способов. и во всех этих случаях результат будет получаться один и тот же. будет меняться только запись способа того, как результат получается.
если учесть, что сейчас во всю используется подход, что в ФЯ, что в ООП, что в других парадигмах — что неизменным должен оставаться только наблюдаемый результат, то получается что все спецификации, который специфицирует один и тот же результат для одной и той же записи, а отличаются лишь способами расчета — одинаковые, и соответственно раздел "как" спецификации становится неважным, он лишь необходим чтобы можно было восстановить спецификацию результата.
DG>возьмем запись "1 + 2 * 3", ее можно специфицировать через вычислитель (стековую машину), можно через правила математики, можно еще стопятнадцатью способов. и во всех этих случаях результат будет получаться один и тот же. будет меняться только запись способа того, как результат получается.
Ну, во-первых, не во всех. Мы можем придать ей императивную семантику таким образом, что 2 * 3 будет означать "format C:". Не читая спецификацию, проверить это нельзя.
DG>если учесть, что сейчас во всю используется подход, что в ФЯ, что в ООП, что в других парадигмах — что неизменным должен оставаться только наблюдаемый результат, то получается что все спецификации, который специфицирует один и тот же результат для одной и той же записи, а отличаются лишь способами расчета — одинаковые, и соответственно раздел "как" спецификации становится неважным, он лишь необходим чтобы можно было восстановить спецификацию результата.
Во-вторых то, что некоторые императивные программы внешне похожи на декларативные, ничего не означает. Например, на стандартной клавиатуре латинская C и кириллическая С расположены на одной и той же кнопке. Говорит ли это о том, что латиницу и кириллицу можно считать одинаковами?
Теперь вернёмся к спецификациям. Чтобы спецификации они были одинаковыми, недостаточно того, чтобы они приводили к одинаковым результатам для какой-то одной программы. Нужно, чтобы они приводили к одинаковым результатам для любой программы. Так что все разделы спецификации внезапно оказываются важными.
Но всё это — бессмысленное обсуждение. Вы опять пытаетесь классифицировать декларативные и императивные программы на основе признаков, которые не дают корректных результатов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Ну, во-первых, не во всех. Мы можем придать ей императивную семантику таким образом, что 2 * 3 будет означать "format C:". Не читая спецификацию, проверить это нельзя.
можем. но при этом достаточно читать спецификацию результата, спецификацию вычислителя можно не читать.
или если нет спецификации результата, то можно прочитать спецификацию вычислителя — восстановить спецификацию результата, а спецификацию вычислителя выкинуть, и получать специфицированный результат как хочется.
S>Во-вторых то, что некоторые императивные программы внешне похожи на декларативные, ничего не означает. Например, на стандартной клавиатуре латинская C и кириллическая С расположены на одной и той же кнопке. Говорит ли это о том, что латиницу и кириллицу можно считать одинаковами?
что в этом примере является результатом?
S>Теперь вернёмся к спецификациям. Чтобы спецификации они были одинаковыми, недостаточно того, чтобы они приводили к одинаковым результатам для какой-то одной программы.
S> Нужно, чтобы они приводили к одинаковым результатам для любой программы. Так что все разделы спецификации внезапно оказываются важными.
реальным людям необходимы одинаковые результаты в один в один на много меньшем подмножестве программ, а именно на подмножестве осмысленных и корректных программ.
и этим же реальным людям для неосмысленных и некорректных программ достаточно того, что тем или иным способом возвращается ошибка (одинаковость fail-а уже никто и не ожидает)
90% спецификации (если не 99%) обычно специфицируют результат для некорректных или вырожденных случаев. при этом в реальной программе это всё не используется, а значит не влияет на результат и может быть выброшено.
Здравствуйте, DarkGray, Вы писали: DG>можем. но при этом достаточно читать спецификацию результата, спецификацию вычислителя можно не читать.
Откуда возьмётся "спецификация результата"?
DG>или если нет спецификации результата, то можно прочитать спецификацию вычислителя — восстановить спецификацию результата, а спецификацию вычислителя выкинуть, и получать специфицированный результат как хочется.
Очень хорошо. Для некоторого класса программ — вроде приведённого вами, задача тривиальна. Просто вычисляем-вычисляем, в конце получаем 7 и больше нам ничего считать не надо.
Давайте возьмём пример поинтереснее.
IEnumerable<int> F(IEnumerable<int> source)
{
foreach(var i in source)
{
_a = i ^ (i << (_a &&0x4)) ^ (i >> 16));
yield return i ^ _a;
}
}
private int _a = 42;
Вас не затруднит восстановить спецификацию результата, чтобы мы могли спокойно выкинуть спецификацию вычислителя?
DG>90% спецификации (если не 99%) обычно специфицируют результат для некорректных или вырожденных случаев. при этом в реальной программе это всё не используется, а значит не влияет на результат и может быть выброшено.
Ну и что же из этого следует?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>IEnumerable<int> F(IEnumerable<int> source)
S>{
S> foreach(var i in source)
S> {
S> _a = i ^ (i << (_a &&0x4)) ^ (i >> 16));
S> yield return i ^ _a;
S> }
S>}
S>private int _a = 42;
S>
S>Вас не затруднит восстановить спецификацию результата, чтобы мы могли спокойно выкинуть спецификацию вычислителя?
результат этого кода эквивалентен результату кода
(target, _a) = source.Wave(a:_a, (i, a) =>
{
var di = (i << (a &&0x4)) ^ (i >> 16));
return (di, a:i ^ di);
}
)
wave — это объединение select-а с aggregate/accumulate: обработка каждого значения совмещена с расчетом аккумулятора. и wave эффективно может быть реализован поверх широкого класса вычислителей.
при этом используется, что в реальных программах необходима однозначность значимой части результата, и что одновременно две функции F не исполняются
после такой замены, спецификацию на ienumerable и yield можно выкинуть.
остается только спецификация на операции ^ << >> &&, которая идентичная для большинства языков. за исключением вырожденных случаев.
зы
декларация же может быть задана в виде: результат должен быть таким же, как результат вот такого-то вычисления, а выполнять можете как хотите (и для сложных алгоритмов нет другого способа задания результата)
и возможность такого задания декларации делает тривиальным переход от последовательности вычисления к спецификации результата — достаточно для имеющейся последовательности вычисления сказать: требуется результат, как результат данной программы, а считать можете как хотите.
при этом утверждение "делайте как хотите, главное чтобы результат был тем же самым" и так уже говорится, что для ФЯ, что для ООП и т.д. — что внутреннее поведение неважно, важно чтобы сохранялось внешнее поведение(внешний результат)
DG>>90% спецификации (если не 99%) обычно специфицируют результат для некорректных или вырожденных случаев. при этом в реальной программе это всё не используется, а значит не влияет на результат и может быть выброшено. S>Ну и что же из этого следует?
что две спецификации результата, отличающиеся лишь спецификацией результата для некорректного поведения — для значимой части программ являются одной и той же спецификацией.
S>>IEnumerable<int> F(IEnumerable<int> source)
S>>{
S>> foreach(var i in source)
S>> {
S>> _a = i ^ (i << (_a &&0x4)) ^ (i >> 16));
S>> yield return i ^ _a;
S>> }
S>>}
S>>private int _a = 42;
S>>
S>>Вас не затруднит восстановить спецификацию результата, чтобы мы могли спокойно выкинуть спецификацию вычислителя?
DG>результат этого кода эквивалентен результату кода DG>
DG>(target, _a) = source.Wave(a:_a, (i, a) =>
DG> {
DG> var di = (i << (a &&0x4)) ^ (i >> 16));
DG> return (di, a:i ^ di);
DG> }
DG>)
DG>
DG>wave — это объединение select-а с aggregate/accumulate: обработка каждого значения совмещена с расчетом аккумулятора. и wave эффективно может быть реализован поверх широкого класса вычислителей. DG>при этом используется, что в реальных программах необходима однозначность значимой части результата, и что одновременно две функции F не исполняются
Однозначность значимой части результата — это детерминированность? Если да, то в исходном коде результат недетерминирован, что его отличает от преобразованного. Если нет — что подразумевается под однозначностью значимой части результата?
DG>после такой замены, спецификацию на ienumerable и yield можно выкинуть. DG>остается только спецификация на операции ^ << >> &&, которая идентичная для большинства языков. за исключением вырожденных случаев.
Только нужна спецификация двоеточия, Wave, "скобочек". Мне вот с разбегу не понятно, почему кортеж должен быть эквивалентен IEnumerable.
S>Однозначность значимой части результата — это детерминированность?
зная твою тягу к буквоедству, не готов ничего сказать про детерминированность, пока не будет определения этого термина через более базовые понятия.
однозначность X от Y — при одинаковых значениях Y получаются одинаковые значения X
однозначность реального кода — однозначность значимой части результа относительно значимой части входа и значимых условий выполнения
значимая часть — это та часть, которую мы принимаем во внимание.
S> Если да, то в исходном коде результат недетерминирован, что его отличает от преобразованного.
результат исходной функции F однозначен относительно состояния последовательности source и состояния переменной a, при условии что параллельно не выполняются две функции F
S> Если нет — что подразумевается под однозначностью значимой части результата?
DG>>после такой замены, спецификацию на ienumerable и yield можно выкинуть. DG>>остается только спецификация на операции ^ << >> &&, которая идентичная для большинства языков. за исключением вырожденных случаев.
S>Только нужна спецификация двоеточия, Wave, "скобочек". Мне вот с разбегу не понятно, почему кортеж должен быть эквивалентен IEnumerable.
есть такая проблема.
и она возникает даже на классическом варианте с сортировкой: когда результат специфицируется проще, чем выполнение.
все равно, чтобы зафиксировать требования к результату сортировки необходимо сначала ввести хоть какого-нибудь исполнителя и операции над ним. чтобы однозначно записать, что такое отсортированная последовательность.
Здравствуйте, DarkGray, Вы писали:
S>>Однозначность значимой части результата — это детерминированность?
DG>зная твою тягу к буквоедству, не готов ничего сказать про детерминированность, пока не будет определения этого термина через более базовые понятия.
Зная твою тягу к называнию каких-то своих понятий общеупотребимыми словами, пытаюсь уточнить о чем речь сразу.
DG>однозначность X от Y — при одинаковых значениях Y получаются одинаковые значения X
А X при этом должен себя вести однозначно? Считается ли по-твоему однозначной зависимость X от того, сколько раз его спросили о чем-то? Должен ли X.First() == X.First()?
DG>однозначность реального кода — однозначность значимой части результа относительно значимой части входа и значимых условий выполнения
DG>значимая часть — это та часть, которую мы принимаем во внимание.
Ты принимаешь во внимание что результирующая последовательность изменяется при обращении к ней?
S>> Если да, то в исходном коде результат недетерминирован, что его отличает от преобразованного.
DG>результат исходной функции F однозначен относительно состояния последовательности source и состояния переменной a, при условии что параллельно не выполняются две функции F
А что касается (target, _a), будет ли оно однозначной?
S>>Только нужна спецификация двоеточия, Wave, "скобочек". Мне вот с разбегу не понятно, почему кортеж должен быть эквивалентен IEnumerable.
DG>есть такая проблема. DG>и она возникает даже на классическом варианте с сортировкой: когда результат специфицируется проще, чем выполнение. DG>все равно, чтобы зафиксировать требования к результату сортировки необходимо сначала ввести хоть какого-нибудь исполнителя и операции над ним. чтобы однозначно записать, что такое отсортированная последовательность.
Зачем тут исполнитель? Упорядоченность по ключу определяет остортированноую последовательность. Для однозначности можно потребовать устойчивость. Какая разница, какой исполнитель сортировал?
DG>>все равно, чтобы зафиксировать требования к результату сортировки необходимо сначала ввести хоть какого-нибудь исполнителя и операции над ним. чтобы однозначно записать, что такое отсортированная последовательность. S>Зачем тут исполнитель? Упорядоченность по ключу определяет остортированноую последовательность. Для однозначности можно потребовать устойчивость. Какая разница, какой исполнитель сортировал?
передергиваешь. я не говорил, что нужен исполнитель для сортировки.
я говорил, что нужен исполнитель для того, чтобы выполнить условие накладываемое на результат сортировки.
однозначная трактовка предиката "каждое следующее неменьше предыдущего" или "для любой пары ti, tj результирующей последовательности при i >= j должно выполняться условие cmp(ti, tj) >= 0" и т.д. — не дана каждому свыше, а значит каждый может трактовать ее по своему. и чтобы все трактовали этот предикат однозначно, необходимо ввести вычислитель и правила вычисления.
и в любой алгебре (логическая алгебра, элементарная алгебра и т.д.) именно это и делается.
DG>>однозначность X от Y — при одинаковых значениях Y получаются одинаковые значения X S>А X при этом должен себя вести однозначно?
однозначно от какого входа?
S> Считается ли по-твоему однозначной зависимость X от того, сколько раз его спросили о чем-то?
не важно, здесь рассматривается уже другой выход относительного другого входа
S> Должен ли X.First() == X.First()?
определенного вывода сделать нельзя. очень много зависит от нюансов.
например, смотря как определена операция равенства для X. например, если X.First() в это сравнение вообще не входит, то на X.First() == X.First() вообще пофигу
S> Ты принимаешь во внимание что результирующая последовательность изменяется при обращении к ней?
значимость этого зависит от того, как определены рассматриваемые вход и выход
DG>результат исходной функции F однозначен относительно состояния последовательности source и состояния переменной a, при условии что параллельно не выполняются две функции F
SS>А что касается (target, _a), будет ли оно однозначной?
Здравствуйте, DarkGray, Вы писали:
DG>>>все равно, чтобы зафиксировать требования к результату сортировки необходимо сначала ввести хоть какого-нибудь исполнителя и операции над ним. чтобы однозначно записать, что такое отсортированная последовательность. S>>Зачем тут исполнитель? Упорядоченность по ключу определяет остортированноую последовательность. Для однозначности можно потребовать устойчивость. Какая разница, какой исполнитель сортировал?
DG>передергиваешь. я не говорил, что нужен исполнитель для сортировки. DG>я говорил, что нужен исполнитель для того, чтобы выполнить условие накладываемое на результат сортировки.
Что значит выполнить условие? Я понимаю так: есть результат, есть условие, которое либо выполняется, либо нет. Исполнитель может отстортировать, может проверить условие. Но выполнить условие
Лучше вернемся к термину "зафиксировать требования". Так вот, требованиям должна удовлетворять результирующая последовательность. И должна она этим требованиям удовлетворять вне зависимости от исполнителя и от того, как ты эти требования запишешь в коде для конкретного исполнителя. Это если, конечно, тебя интересует результирующая последовательность, а не сам процесс фиксирования требований для конкретного исполнителя.
DG>однозначная трактовка предиката "каждое следующее неменьше предыдущего" или "для любой пары ti, tj результирующей последовательности при i >= j должно выполняться условие cmp(ti, tj) >= 0" и т.д. — не дана каждому свыше, а значит каждый может трактовать ее по своему.
Слушай, термин "порядок" определен однозначно свыше. Только ты трактуешь термины по-своему.
DG>и чтобы все трактовали этот предикат однозначно, необходимо ввести вычислитель и правила вычисления.
Обычно все немного наоборот. Сначала формулируются требования к результату, потом они (либо инструкции по получению результата) записываются в коде для определенного вычислителя согласно его правилам вычисления.
DG>и в любой алгебре (логическая алгебра, элементарная алгебра и т.д.) именно это и делается.
Не так давно ты предлагал отказаться от обсуждения терминов вообще, теперь же хочешь однозначности трактовки.
DG>>>однозначность X от Y — при одинаковых значениях Y получаются одинаковые значения X S>>А X при этом должен себя вести однозначно?
DG>однозначно от какого входа?
От самого себя, например.
S>> Считается ли по-твоему однозначной зависимость X от того, сколько раз его спросили о чем-то?
DG>не важно, здесь рассматривается уже другой выход относительного другого входа
S>> Должен ли X.First() == X.First()?
DG>определенного вывода сделать нельзя. очень много зависит от нюансов. DG>например, смотря как определена операция равенства для X. например, если X.First() в это сравнение вообще не входит, то на X.First() == X.First() вообще пофигу
Речь все еще о примере Синклера с IEnumerable<int>. Вопрос был об однозначности результата той функции F. Будет ли он "однозначным" по твоему (ты же отказался обсуждать детерминированность, а я пытаюсь понять, что ты под однозначностью понимаешь с ньюансами)?
var X = F(new int[]{1, 2, 3});
Console.WriteLine(X.First() == X.First()); // Допускает ли твоя однозначность здесь False?
S>> Ты принимаешь во внимание что результирующая последовательность изменяется при обращении к ней?
DG>значимость этого зависит от того, как определены рассматриваемые вход и выход
См пример Синклера
DG>>результат исходной функции F однозначен относительно состояния последовательности source и состояния переменной a, при условии что параллельно не выполняются две функции F
SS>>А что касается (target, _a), будет ли оно однозначной?
DG>(target, _a) однозначен от (source, _a)
У чего тут первый член брать? И как проверить, будет ли он равен первому члену, запрошенному еще раз у того же результата?
DG>>передергиваешь. я не говорил, что нужен исполнитель для сортировки. DG>>я говорил, что нужен исполнитель для того, чтобы выполнить условие накладываемое на результат сортировки. S>Что значит выполнить условие? Я понимаю так: есть результат, есть условие, которое либо выполняется, либо нет. Исполнитель может отстортировать, может проверить условие. Но выполнить условие
как ты собираешься проверять условие без выполнения чего-либо?
DG>>однозначная трактовка предиката "каждое следующее неменьше предыдущего" или "для любой пары ti, tj результирующей последовательности при i >= j должно выполняться условие cmp(ti, tj) >= 0" и т.д. — не дана каждому свыше, а значит каждый может трактовать ее по своему. S>Слушай, термин "порядок" определен однозначно свыше. Только ты трактуешь термины по-своему.
никакого свыше нет. "порядок" даже не является аксиоматическим понятием.
DG>>и чтобы все трактовали этот предикат однозначно, необходимо ввести вычислитель и правила вычисления. S>Обычно все немного наоборот. S> Сначала формулируются требования к результату,
в виде алгоритма для абстрактного вычислителя
S> потом они (либо инструкции по получению результата) записываются в коде для определенного вычислителя согласно его правилам вычисления.
потом исходный алгоритм для абстрактного вычислителя преобразуется в алгоритм для определенного вычислителя
DG>>и в любой алгебре (логическая алгебра, элементарная алгебра и т.д.) именно это и делается. S>Не так давно ты предлагал отказаться от обсуждения терминов вообще, теперь же хочешь однозначности трактовки.
я говорил, что фиксировать термины без фиксирования задачи не имеет смысл.
S>Речь все еще о примере Синклера с IEnumerable<int>. Вопрос был об однозначности результата той функции F. Будет ли он "однозначным" по твоему (ты же отказался обсуждать детерминированность, а я пытаюсь понять, что ты под однозначностью понимаешь с ньюансами)?
S>
S>var X = F(new int[]{1, 2, 3});
S>Console.WriteLine(X.First() == X.First()); // Допускает ли твоя однозначность здесь False?
S>
для функции синклера здесь конечно может быть false, как минимум потому что функция F выполняется параллельно, и я специально оговорил, что при параллельном выполнении F однозначности добиться будет трудно. и что поэтому едва ли такое использование функции F можно рассматривать как реальное.
вот такой код, кстати, уже всегда будет true
var source = new int[]{1, 2, 3};
_a = 42;
var X1 = F(source);
var x1_f = X1.First();
_a = 42;
var X2 = F(source);
var x2_f = X2.first();
Console.WriteLine(x1_f == x2_f); // Допускает ли твоя однозначность здесь False?
S>>> Ты принимаешь во внимание что результирующая последовательность изменяется при обращении к ней?
DG>>значимость этого зависит от того, как определены рассматриваемые вход и выход S>См пример Синклера
для нее не оговорено, что есть вход и выход
DG>>>результат исходной функции F однозначен относительно состояния последовательности source и состояния переменной a, при условии что параллельно не выполняются две функции F
SS>>>А что касается (target, _a), будет ли оно однозначной?
DG>>(target, _a) однозначен от (source, _a) S>У чего тут первый член брать? И как проверить, будет ли он равен первому члену, запрошенному еще раз у того же результата?
брать у target
вызвать один и тот же Wave(..) для одних и тех же (source, _a)
DG>>>передергиваешь. я не говорил, что нужен исполнитель для сортировки. DG>>>я говорил, что нужен исполнитель для того, чтобы выполнить условие накладываемое на результат сортировки. S>>Что значит выполнить условие? Я понимаю так: есть результат, есть условие, которое либо выполняется, либо нет. Исполнитель может отстортировать, может проверить условие. Но выполнить условие
DG>как ты собираешься проверять условие без выполнения чего-либо?
Линейкой. Мерили ведь раньше без выполнения чего-либо.
DG>>>однозначная трактовка предиката "каждое следующее неменьше предыдущего" или "для любой пары ti, tj результирующей последовательности при i >= j должно выполняться условие cmp(ti, tj) >= 0" и т.д. — не дана каждому свыше, а значит каждый может трактовать ее по своему. S>>Слушай, термин "порядок" определен однозначно свыше. Только ты трактуешь термины по-своему.
DG>никакого свыше нет. "порядок" даже не является аксиоматическим понятием.
Аксиоматическим — нет. Но когда клиент говорит что ему нужна упорядоченная последовательность, то возникает вопрос лишь "по какому признаку", а не о том, как трактовать "порядок".
DG>>>и чтобы все трактовали этот предикат однозначно, необходимо ввести вычислитель и правила вычисления. S>>Обычно все немного наоборот. S>> Сначала формулируются требования к результату,
DG>в виде алгоритма для абстрактного вычислителя
Требования к результату могут быть выражены без алгоритма абстрактного вычислителя. Например: по росту. Всё. Где здесь алгоритм? Где вычислитель?
S>> потом они (либо инструкции по получению результата) записываются в коде для определенного вычислителя согласно его правилам вычисления.
DG>потом исходный алгоритм для абстрактного вычислителя преобразуется в алгоритм для определенного вычислителя
Определенный вычислитель может не пользоваться алгоритмами явно.
DG>>>и в любой алгебре (логическая алгебра, элементарная алгебра и т.д.) именно это и делается. S>>Не так давно ты предлагал отказаться от обсуждения терминов вообще, теперь же хочешь однозначности трактовки.
DG>я говорил, что фиксировать термины без фиксирования задачи не имеет смысл.
Если ты их не фиксировал, почему их употребляешь?
S>>Речь все еще о примере Синклера с IEnumerable<int>. Вопрос был об однозначности результата той функции F. Будет ли он "однозначным" по твоему (ты же отказался обсуждать детерминированность, а я пытаюсь понять, что ты под однозначностью понимаешь с ньюансами)?
S>>
S>>var X = F(new int[]{1, 2, 3});
S>>Console.WriteLine(X.First() == X.First()); // Допускает ли твоя однозначность здесь False?
S>>
DG>для функции синклера здесь конечно может быть false, как минимум потому что функция F выполняется параллельно, и я специально оговорил, что при параллельном выполнении F однозначности добиться будет трудно. и что поэтому едва ли такое использование функции F можно рассматривать как реальное.
Никаких параллельно. Что ты вообще подразумеваешь под параллельно? Многозадачность? Ее здесь нет.
DG>вот такой код, кстати, уже всегда будет true
DG>
А кто будет сбрасывать _a в начальное состояние в примере Синклера?
DG>>>значимость этого зависит от того, как определены рассматриваемые вход и выход S>>См пример Синклера
DG>для нее не оговорено, что есть вход и выход
И ты при этом не постеснялся заявить что твой код является эквивалентным?
DG>>>>результат исходной функции F однозначен относительно состояния последовательности source и состояния переменной a, при условии что параллельно не выполняются две функции F
SS>>>>А что касается (target, _a), будет ли оно однозначной?
DG>>>(target, _a) однозначен от (source, _a) S>>У чего тут первый член брать? И как проверить, будет ли он равен первому члену, запрошенному еще раз у того же результата?
DG>брать у target DG>вызвать один и тот же Wave(..) для одних и тех же (source, _a)
Ну и о какой эквивалентности речь, если target "однозначен", а результат исходного примера нет?
DG>>для функции синклера здесь конечно может быть false, как минимум потому что функция F выполняется параллельно, и я специально оговорил, что при параллельном выполнении F однозначности добиться будет трудно. и что поэтому едва ли такое использование функции F можно рассматривать как реальное. S>Никаких параллельно. Что ты вообще подразумеваешь под параллельно? Многозадачность? Ее здесь нет.
многозадачности нет, а параллельность есть. строки кода функции F выполняются параллельно в данном примере, это можно, например, увидеть если поставить breakpoint-ы в функцию F. функция F вызовется дважды, при этом второй вызов функции F начнется раньше, чем полностью закончится первый.
S>А кто будет сбрасывать _a в начальное состояние в примере Синклера?
например, строка private int _a = 42 из исходного кода, если пример Синклера будет запускаться как несколько экземпляров программ.
DG>>>>значимость этого зависит от того, как определены рассматриваемые вход и выход S>>>См пример Синклера
DG>>для нее не оговорено, что есть вход и выход S>И ты при этом не постеснялся заявить что твой код является эквивалентным?
я привел условия, при которых я считаю, что данные два кода эквивалентные. привел, конечно, не все условия, а только неочевидные.
DG>>как ты собираешься проверять условие без выполнения чего-либо? S>Линейкой. Мерили ведь раньше без выполнения чего-либо.
чтобы измерить линейкой уже необходим исполнитель в виде человека с инструкцией, что такое линейка, куда ее прикладывать, какой стороной, и на что смотреть.
DG>>никакого свыше нет. "порядок" даже не является аксиоматическим понятием. S>Аксиоматическим — нет. Но когда клиент говорит что ему нужна упорядоченная последовательность, то возникает вопрос лишь "по какому признаку", а не о том, как трактовать "порядок".
это как-то доказывает, что все люди трактуют понятие "упорядоченная последовательность" однозначным способом?
DG>>в виде алгоритма для абстрактного вычислителя S>Требования к результату могут быть выражены без алгоритма абстрактного вычислителя. Например: по росту. Всё. Где здесь алгоритм? Где вычислитель?
что "по росту"?
S>>> потом они (либо инструкции по получению результата) записываются в коде для определенного вычислителя согласно его правилам вычисления.
DG>>потом исходный алгоритм для абстрактного вычислителя преобразуется в алгоритм для определенного вычислителя S>Определенный вычислитель может не пользоваться алгоритмами явно.
пример такого вычислителя
DG>>>>и в любой алгебре (логическая алгебра, элементарная алгебра и т.д.) именно это и делается. S>>>Не так давно ты предлагал отказаться от обсуждения терминов вообще, теперь же хочешь однозначности трактовки.
DG>>я говорил, что фиксировать термины без фиксирования задачи не имеет смысл. S>Если ты их не фиксировал, почему их употребляешь?
потому что это эффективный способ общения. Понятия используются без жесткой фиксации, каждый из собеседников их сам восстанавливает до непротиворечивого состояния из контекста на основе своих алгоритмов. Если в ходе беседы выясняется, что понятия восстанавливаются по разному (например, на основе того, что выводы у собеседников получаются разные), то сравниваются алгоритмы используемые для определения и восстановления понятий
Здравствуйте, DarkGray, Вы писали:
DG>>>как ты собираешься проверять условие без выполнения чего-либо? S>>Линейкой. Мерили ведь раньше без выполнения чего-либо.
DG>чтобы измерить линейкой уже необходим исполнитель в виде человека с инструкцией, что такое линейка, куда ее прикладывать, какой стороной, и на что смотреть.
Кому как
DG>>>никакого свыше нет. "порядок" даже не является аксиоматическим понятием. S>>Аксиоматическим — нет. Но когда клиент говорит что ему нужна упорядоченная последовательность, то возникает вопрос лишь "по какому признаку", а не о том, как трактовать "порядок".
DG>это как-то доказывает, что все люди трактуют понятие "упорядоченная последовательность" однозначным способом?
Это как раз доказывает что есть люди, которые считают что понятие "упорядоченная последовательность" неоднозначно. Хотя на самом деле оно однозначно.
DG>>>в виде алгоритма для абстрактного вычислителя S>>Требования к результату могут быть выражены без алгоритма абстрактного вычислителя. Например: по росту. Всё. Где здесь алгоритм? Где вычислитель?
DG>что "по росту"?
Это требование к результату.
S>>>> потом они (либо инструкции по получению результата) записываются в коде для определенного вычислителя согласно его правилам вычисления.
DG>>>потом исходный алгоритм для абстрактного вычислителя преобразуется в алгоритм для определенного вычислителя S>>Определенный вычислитель может не пользоваться алгоритмами явно.
DG>пример такого вычислителя
Например, если принять за вычислитель человека, то для проверки требования "по росту" ему достаточно "прикинуть на глазок", не объясняя алгоритмов и куда прикладывать линейку.
DG>>>я говорил, что фиксировать термины без фиксирования задачи не имеет смысл. S>>Если ты их не фиксировал, почему их употребляешь?
DG>потому что это эффективный способ общения. Понятия используются без жесткой фиксации, каждый из собеседников их сам восстанавливает до непротиворечивого состояния из контекста на основе своих алгоритмов. Если в ходе беседы выясняется, что понятия восстанавливаются по разному (например, на основе того, что выводы у собеседников получаются разные), то сравниваются алгоритмы используемые для определения и восстановления понятий
Я считаю что ты не можешь называть свое общение здесь эффективным. Вот пример из другого форума
зафиксировали что есть последовательность писем (и отдельно отмечу, что слово последовательность здесь лишь означает, что писем много, что можно считать, что они примерно одного и того же типа, и что их можно перебрать тем или иным способом, и не означает, что письма хранятся в виде последовательности)
Эффективным было бы сказать "есть множество писем", уповая на то, что собеседник знает что такое множество, а не объяснять что под последовательностью ты подразумеваешь множество, вопреки понятию "последовательность".
В итоге выходит что ты употребляешь термины без жесктой фиксации, а собеседники должны все время догадываться, в каком смысле ты их употребил, потому как неизбежно возникают противоречия (см. так же чистоту с побочными эффектами), которые и порождает массу флуда.
это уже слишком банальный пример, и для него функция F восстанавливается как другой однозначный вариант функции F(более простой) и HelloSum. при этом наличие нескольких восстановленных функций F ничему не мешают.
HellSum(source)=>source.F_2().Sum();
F_2(source)=>source.Select(i => i ^ (i >> 16));
или так
HellSum(source)=>source.F_2(a:0).Sum();
F_2(source, a)=>source.Select(i => (i << (a &&0x4)) ^ (i >> 16));
т.е. как только появляется реальный код для которого выполняется однозначность, по нему всегда можно восстановить спецификацию результата.
и здесь тоже можно выкинуть спецификации на yield, ienumerable и foreach
DG>>декларация же может быть задана в виде: результат должен быть таким же, как результат вот такого-то вычисления, а выполнять можете как хотите (и для сложных алгоритмов нет другого способа задания результата) S>Как интересно. То есть вы настаиваете, что разницы между декларативным и императивным описаниями нет. Тогда объясните это vdimas-у, а то он почему-то считает РА более императивной, чем РИ.
нет четкой границы, где заканчивается декларативная программа и начинается императивная (и соответственно, черно/белый подход — декларативная/императивная имеет очень низкую полезность)
при этом можно использовать сравнительную степень более декларативная/менее декларативная на той или иной метрике декларативности
DG>>при этом утверждение "делайте как хотите, главное чтобы результат был тем же самым" и так уже говорится, что для ФЯ, что для ООП и т.д. — что внутреннее поведение неважно, важно чтобы сохранялось внешнее поведение(внешний результат) S>Вы движетесь в правильную сторону. Остаётся понять, что такое "внешнее поведение", и вы сможете отличить декларативную программу от императивной.
я знаю, что это такое.
а вот samius и ты похоже не понимаете что такое спецификация результата, как и на чем она пишется. скорее всего это означает, что вы либо на прологе(или аналоге) вообще ничего не писали, или не писали сложные вещи.
DG>>что две спецификации результата, отличающиеся лишь спецификацией результата для некорректного поведения — для значимой части программ являются одной и той же спецификацией. S>Отлично. Осталось определить, что такое "корректное поведение", что такое "некорректное поведение", и что такое "результат". А то вот вы взяли и "исправили" мою программу, написав свою. Да, "результат" работы вашей программы иногда получается таким же, как и у моей программы.
S>Но ведь тогда я могу в некоторой библиотеке заменить вычисление синуса на return 0; сказав, что во всех корректных программах аргумент всегда равен нулю, а те, кто передаёт не ноль — сами виноваты. Чем моя аргументация будет хуже вашей? Она столь же произвольна.
ты перепрыгиваешь:
во-первых, от реальных программ к библиотекам
во-вторых, к правилам хорошего тона для кодирования.
ни то, ни другое не имеет никакого отношения к тому, что по реальной программе (на которую накладывается лишь требование однозначности) можно восстановить спецификацию результата, и выкинуть спецификацию вычислителя
я согласен с тем, что правила "хорошо пахнущего кода" упрощают восстановление спецификации результата
S> Это как раз доказывает что есть люди, которые считают что понятие "упорядоченная последовательность" неоднозначно. Хотя на самом деле оно однозначно.
выйди на улицу. и спроси у первых двадцати прохожих, что такое "упорядоченная последовательность" и запиши.
для проверки понимания также стоит спросить, как они будут проверять, что последовательность упорядочена, и каких действий достаточно для проверки упорядоченности.
на сколько я знаю, тебя ждут сюрпризы
S>Эффективным было бы сказать "есть множество писем", уповая на то, что собеседник знает что такое множество, а не объяснять что под последовательностью ты подразумеваешь множество, вопреки понятию "последовательность".
вот только проблема в том, что для C#-программиста и математика понятия множество, коллекция, последовательность и т.д. отличаются.
для программистов пишушего на других языках эти понятия тоже будут иметь свое понимание.
для C#-программиста последовательность более общее понятие, чем множество. т.к у последовательности есть только требование перебора элементов, а у множества уже появляется требование сравнимости элементов, проверка наличия элемента за O(1) и т.д.
коллекция — это последовательность для которой известно количество.
и это понимание понятий последовательность, коллекция и множество формируется на основе .net-интерфейсов: IEnumerable, ICollection, ISet
для математика наоборот множество более общее понятие, чем последовательность, потому что первое может не иметь способа перебора элементов, а для последовательности уже задан способ перебора элементов.
и для большинства понятий это нормальное явление, что в каждой области свое толкование одного и того же понятия.
S>Эффективным было бы сказать "есть множество писем", уповая на то, что собеседник знает что такое множество, а не объяснять что под последовательностью ты подразумеваешь множество, вопреки понятию "последовательность".
другие виды общения еще менее эффективные.
в качестве примера можно взять этот тред: копий вокруг трактовки терминов сломано много, а по сути сообщений не так уж и много,
при этом и введение терминов не помогало — как только вводятся термины, то их вообще никто не читает — посмотри сколько сообщений в ветке относительное ООП, или в ветке л-существования.
и это в часности вызвано тем, что человек имеет очень ограниченные способности по усвоению понятий (одна из оценок в 2^16)
и это означает, что человеку доступно лишь 16 последовательных развилок в трактовании терминов.
Здравствуйте, DarkGray, Вы писали:
S>> Это как раз доказывает что есть люди, которые считают что понятие "упорядоченная последовательность" неоднозначно. Хотя на самом деле оно однозначно.
DG>выйди на улицу. и спроси у первых двадцати прохожих, что такое "упорядоченная последовательность" и запиши. DG>для проверки понимания также стоит спросить, как они будут проверять, что последовательность упорядочена, и каких действий достаточно для проверки упорядоченности.
DG>на сколько я знаю, тебя ждут сюрпризы
Тут все просто. Понятие однозначно, но его могут не знать. то что человек не может сформулировать даже интуитивно ему понятное — не значит, что он пользуется другим понятием. Человек с улицы не показатель однозначности понятия.
Но ты же вкладываешь свой смысл в термины при общении с теми, кому известно их значение, кому приходится работать с этими определениями. И называешь это эффективным. Эффект один — озадачивание собеседника. Если ты своими полетами мысли добиваешься именно этого, то да, прием эффективный.
S>>Эффективным было бы сказать "есть множество писем", уповая на то, что собеседник знает что такое множество, а не объяснять что под последовательностью ты подразумеваешь множество, вопреки понятию "последовательность".
DG>вот только проблема в том, что для C#-программиста и математика понятия множество, коллекция, последовательность и т.д. отличаются.
Не может быть. Есть понятия — математические абстракции, есть частные реализации этих абстракций. То, о чем именно в данном случае речь, можно понять из контекста, если об этом не сказано напрямую. Но контейнер System.Collections.Generic.Set никак не подменяет понятие математической абстракции "множество". DG>для программистов пишушего на других языках эти понятия тоже будут иметь свое понимание.
DG>для C#-программиста последовательность более общее понятие, чем множество. т.к у последовательности есть только требование перебора элементов, а у множества уже появляется требование сравнимости элементов, проверка наличия элемента за O(1) и т.д.
Тут ты говоришь не о понятиях, а о реализациях. Причем с требованием проверки наличия за O(1) ты явно загнул. Опровержение тому — OrderedSet.
DG>коллекция — это последовательность для которой известно количество. DG>и это понимание понятий последовательность, коллекция и множество формируется на основе .net-интерфейсов: IEnumerable, ICollection, ISet
Формировать понятия о математических асбтракциях на основе .net интерфейсов — это ошибка природы.
DG>для математика наоборот множество более общее понятие, чем последовательность, потому что первое может не иметь способа перебора элементов, а для последовательности уже задан способ перебора элементов.
DG>и для большинства понятий это нормальное явление, что в каждой области свое толкование одного и того же понятия.
Теперь я понял, ты в форуме декларативного программирования в русле разговора о хаскеле объяснял собеседнику о смысле понятия, которое ты вкладываешь в слово "последовательность" на основе понятия IEnumerable из .net. И при этом сказал что письма просто хранятся в последовательности, а на самом деле их просто много...
Браво, что тут сказать
Здравствуйте, DarkGray, Вы писали:
S>>Эффективным было бы сказать "есть множество писем", уповая на то, что собеседник знает что такое множество, а не объяснять что под последовательностью ты подразумеваешь множество, вопреки понятию "последовательность".
DG>другие виды общения еще менее эффективные. DG>в качестве примера можно взять этот тред: копий вокруг трактовки терминов сломано много, а по сути сообщений не так уж и много, DG>при этом и введение терминов не помогало — как только вводятся термины, то их вообще никто не читает — посмотри сколько сообщений в ветке относительное ООП, или в ветке л-существования.
Этот тред показателен тем, что вместо того что бы использовать общепринятые определения, ты выдумывал свои.
DG>и это в часности вызвано тем, что человек имеет очень ограниченные способности по усвоению понятий (одна из оценок в 2^16) DG>и это означает, что человеку доступно лишь 16 последовательных развилок в трактовании терминов.
Какой смысл вообще о чем-то разговаривать, если собеседник не понимает о чем ты говоришь, и только и делает что пытается вытащить у тебя смысл, который ты вкладываешь в устоявшиеся термины? Каким образом вообще нужно строить беседу, если в течении беседы оказывается что ты используешь термины таким образом, что это противоречит их определениям?
Здравствуйте, DarkGray, Вы писали:
S>>Вот такого примера достаточно:
DG>это уже слишком банальный пример, и для него функция F восстанавливается как другой однозначный вариант функции F(более простой) и HelloSum. DG>т.е. как только появляется реальный код для которого выполняется однозначность, по нему всегда можно восстановить спецификацию результата.
Я правильно понимаю, что для каждого примера применения функции F вы предлагаете отдельные варианты функции F?
1. К сожалению, вопросы реального программирования не исчерпываются разработкой программ для выполнения фиксированного алгоритма над фиксированным набором входных данных.
2. Варианты преобразований, которые вы предлагаете, не сохраняют эквивалентность с исходной программой. В этом, собственно, и состоит проблема перевода императивной программы в декларативную форму.
DG>нет четкой границы, где заканчивается декларативная программа и начинается императивная (и соответственно, черно/белый подход — декларативная/императивная имеет очень низкую полезность) DG>при этом можно использовать сравнительную степень более декларативная/менее декларативная на той или иной метрике декларативности
Ок, мы всё ещё с нетерпением ждём примера этой метрики. Ваши предыдущие попытки ввести такую метрику были, скажем так, неудачны. DG>я знаю, что это такое. DG>а вот samius и ты похоже не понимаете что такое спецификация результата, как и на чем она пишется. скорее всего это означает, что вы либо на прологе(или аналоге) вообще ничего не писали, или не писали сложные вещи.
О, ещё один телепат в форуме. Ок, предположим, вы правы. Мы с samius никогда не писали программ сложнее Hello World и алгоритмов сложнее bubblesort. Вы, надо полагать, писали. Почему же тогда у вас восстановление спецификации результата по спецификации протокола вызывает такие затруднения?
S>>Но ведь тогда я могу в некоторой библиотеке заменить вычисление синуса на return 0; сказав, что во всех корректных программах аргумент всегда равен нулю, а те, кто передаёт не ноль — сами виноваты. Чем моя аргументация будет хуже вашей? Она столь же произвольна.
DG>ты перепрыгиваешь: DG>во-первых, от реальных программ к библиотекам
А чем отличается библиотека от реальной программы? Вы не спешите отвечать, а то опять получится ерунда. DG>во-вторых, к правилам хорошего тона для кодирования.
Не вижу никакого перехода к правилам хорошего тона. Зачем вы его сюда приплели — совершенно непонятно. Лично я пока что обсуждал только вопросы корректности преобразования программ из императивной формы в декларативную. Вы утверждаете, что это — тривиальное занятие, но при этом весьма несложный случай у вас вызывает затруднения. DG>ни то, ни другое не имеет никакого отношения к тому, что по реальной программе (на которую накладывается лишь требование однозначности) можно восстановить спецификацию результата, и выкинуть спецификацию вычислителя
Ну, моя функция синуса вполне себе однозначна. Просто я предпочёл вот так восстановить спецификацию результата.
DG>я согласен с тем, что правила "хорошо пахнущего кода" упрощают восстановление спецификации результата
Я не понимаю, с чем вы согласны.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>и для большинства понятий это нормальное явление, что в каждой области свое толкование одного и того же понятия. S>Теперь я понял, ты в форуме декларативного программирования в русле разговора о хаскеле объяснял собеседнику о смысле понятия, которое ты вкладываешь в слово "последовательность" на основе понятия IEnumerable из .net.
так как говоришь в математике называется множество с заданной функцией перебора элементов?
DG>>>и для большинства понятий это нормальное явление, что в каждой области свое толкование одного и того же понятия. S>>Теперь я понял, ты в форуме декларативного программирования в русле разговора о хаскеле объяснял собеседнику о смысле понятия, которое ты вкладываешь в слово "последовательность" на основе понятия IEnumerable из .net.
DG>так как говоришь в математике называется множество с заданной функцией перебора элементов?
Если ты о последовательности, то она не является множеством. Потому затрудняюсь ответить, как называется такая пара, особенно безотносительно свойств этой пары.
Лучше прочитай определение последовательности.
DG>>так как говоришь в математике называется множество с заданной функцией перебора элементов? S>Если ты о последовательности, то она не является множеством.
а где ты говоришь учился на математика?
Последовательность — это набор элементов некоторого множества:
для каждого натурального числа можно указать элемент данного множества;
это число является номером элемента и обозначает позицию данного элемента в последовательности;
для любого элемента (члена) последовательности можно указать следующий за ним элемент последовательности.
http://en.wikipedia.org/wiki/Sequence
S> Потому затрудняюсь ответить, как называется такая пара, особенно безотносительно свойств этой пары. S>Лучше прочитай определение последовательности.
хуже невежд только невежественные фанатики, которые считают, что то, что они знают — является полным и окончательным знанием (в частности, считающие — что они-то уж знают, что такое правильное определение терминов)
ps
формальное определение последовательности — это произвольное множество отображенное на множество натуральных чисел.
ззы S>Если ты о последовательности, то она не является множеством.
в последней версии математики вообще ничего кроме множеств нет, даже числа и то вводятся, как множества.
DG>>а вот samius и ты похоже не понимаете что такое спецификация результата, как и на чем она пишется. скорее всего это означает, что вы либо на прологе(или аналоге) вообще ничего не писали, или не писали сложные вещи. S>О, ещё один телепат в форуме. Ок, предположим, вы правы. Мы с samius никогда не писали программ сложнее Hello World и алгоритмов сложнее bubblesort. Вы, надо полагать, писали. Почему же тогда у вас восстановление спецификации результата по спецификации протокола вызывает такие затруднения?
такое ощущение, что ты даже не прочитал мое утверждение. я предполагаю, что ты и samius не писали сложных программ на прологе.
то, что ты можешь писать достаточно сложные программы на одном-двух своих любимых языках верю, особенно в той области в которой набил руку.
vdimas скорее всего сможет осилить более сложные программы, чем ты, а samius более простые чем ты.
при этом твой код скорее всего более четкий и структурированный и проще в поддержке, чем у vdimas-а
Здравствуйте, DarkGray, Вы писали:
DG>такое ощущение, что ты даже не прочитал мое утверждение. я предполагаю, что ты и samius не писали сложных программ на прологе.
Я — прочитал. Просто его можно понять двояко. Ок, поправка принимается. Да, я не писал сложных программ на прологе.
Однако, я не понимаю, какое это отношение имеет к конверсии императивных программ в декларативные?
На всякий случай напомню, что пролог решает обратную задачу. DG>то, что ты можешь писать достаточно сложные программы на одном-двух своих любимых языках верю, особенно в той области в которой набил руку.
DG>vdimas скорее всего сможет осилить более сложные программы, чем ты, а samius более простые чем ты. DG>при этом твой код скорее всего более четкий и структурированный и проще в поддержке, чем у vdimas-а
А вылечить по фотографии от заикания, или, скажем, алкоголизма, у вас возможность есть?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, samius, Вы писали:
DG>>ps DG>>формальное определение последовательности — это произвольное множество отображенное на множество натуральных чисел. S>Произвольное множество, отображенное на множество натуральных чисел, в общем случае не является множеством. S>Вот тебе тривиальный пример { 1, 1, 1, 1, ... }
Вы слишком строги с коллегой DG. Он, конечно же, имел в виду отображение множества натуральных чисел на наше произвольное множество, а не наоборот.
Хотя задать последовательность, конечно же, можно и без прямого указания этого отображения. А, например, при помощи задания на элементах множества отношения полного порядка. Из этого отношения можно восстановить отображение натуральных чисел в элементы множества.
Что характерно, никакой "функции перебора" ни в том, ни в другом случае нет, несмотря на трогательные заблуждения нашего оппонента. Если у нас есть отображение множества натуральных чисел на множество наших элементов, M: x:N->s:S, то нам ничего перебирать не нужно. Можно просто получить s42 = M(42).
Задание "функции перебора" — это третий способ математически определить последовательность, задав функцию Succ: s1:S -> s2:S.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>такое ощущение, что ты даже не прочитал мое утверждение. я предполагаю, что ты и samius не писали сложных программ на прологе. S>Я — прочитал. Просто его можно понять двояко. Ок, поправка принимается. Да, я не писал сложных программ на прологе. S>Однако, я не понимаю, какое это отношение имеет к конверсии императивных программ в декларативные?
Опыт написания сложных программ на языках типа пролога дает понимание, что то, что люди считают однозначным на самом деле таковым не является, и что однозначность появляется только на очень узких задачах.
Здравствуйте, DarkGray, Вы писали:
S>>Что характерно, никакой "функции перебора" ни в том, ни в другом случае нет
DG>если есть отображение множества на множество натуральных чисел, при этом одно натуральное число переходит в один элемент множества, то есть и функция перебора. перебирая натуральные числа перебираются и элементы исходного множества.
Только вот тогда последовательность { 1, 1, 1, 1 } не задать, так как одному элементу множества (1) соответствует аж 4 натуральных. Так что всё же наоборот, отображение натуральных на наше.
Здравствуйте, DarkGray, Вы писали: DG>Опыт написания сложных программ на языках типа пролога дает понимание, что то, что люди считают однозначным на самом деле таковым не является, и что однозначность появляется только на очень узких задачах.
Не понимаю, к чему вы это.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>Вот тебе тривиальный пример { 1, 1, 1, 1, ... }
DG>и каким свойством эта штука не обладает, по которому его можно исключить из класса множеств?
DG>например, берем одно из определений множества DG>
DG>Множество есть совокупность различных элементов, мыслимая как единое целое
DG>элементы есть, совокупность есть, единое целое тоже есть — значит множество.
Экий ты шустрый. Даже System.Collections.Generic.Set такое не позволяет
Здравствуйте, DarkGray, Вы писали:
DG>из одного следует другое. можно лишь поговорить на тему: скольки элементам одного множества сколько элементов другого множества соответствует.
Давайте поговорим. Вот вам отображение множества букв на множество натуральных чисел: A->1 B->1 C->1
Какая последовательность задаётся этим отображением?
Вопрос повышенной сложности: зачем вы продолжаете в этом топике делать заведомо неверные утверждения, даже когда вас поправляют?
DG>если есть отображение множества на множество натуральных чисел, при этом одно натуральное число переходит в один элемент множества, то есть и функция перебора. перебирая натуральные числа перебираются и элементы исходного множества.
В определении порядка таким образом нет никакой функции перебора. То, что её можно построить, в целом очевидно. Но вы-то делали утверждение, что последовательность в математике задаётся именно функцией перебора.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, VoidEx, Вы писали:
VE>А различных есть?
Да это троллинг такой. Берём произвольное определение одной штуки, подразумеваем под ним произвольную другую штуку, причём подменяем определение по ходу дискуссии произвольным образом, и делаем глубокомысленные утверждения на основе этого. Vdimas как-то погрубее троллил, но он уже и слился. А так можно до бесконечности продролжать. Вон, мы уже в трёхзначные глубины вложенности провалились.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
DG>я имел ввиду именно отображение множества на натуральные числа, потому что только в этом случае при переборе по натуральным числам и появляется фальсифицируемость такого отображения, которая и проявится для случая, если мы отобразили два различных элемента множества на одно и то же натуральное число. DG>если мы отображаем натуральные числа на множество и потом по натуральным числам множество и перебираем, то такое отображение не фальсифицируемо (и мы никогда не узнаем, что какие-то исходные элементы множества не перебираются)
Я думаю, что эту ветку дискуссии можно свернуть, т.к. мы упёрлись в предел некомпетентности. Я не могу вести серьёзную беседу с оппонентом, который вводит неработающие определения и отказывается это понимать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>>Вы слишком строги с коллегой DG. Он, конечно же, имел в виду отображение множества натуральных чисел на наше произвольное множество, а не наоборот.
DG>я имел ввиду именно отображение множества на натуральные числа, потому что только в этом случае при переборе по натуральным числам и появляется фальсифицируемость такого отображения, которая и проявится для случая, если мы отобразили два различных элемента множества на одно и то же натуральное число.
Именно отображение X->N позволяет ставить на одно место более одного элемента и не позволяет задавать последовательности с повторяющимися элементами. Чего не скажешь об отображении N->X, которое обычно используется для задания последовательностей.
DG>если мы отображаем натуральные числа на множество и потом по натуральным числам множество и перебираем, то такое отображение не фальсифицируемо (и мы никогда не узнаем, что какие-то исходные элементы множества не перебираются)
Освежи определение отображения. В нем упоминается множество значений, которое определяется отображением. Никакие другие элементы, кроме как из области значений, отображение не должно связывать с областью определения.
Теперь пришла пора мне поинтересоваться, где тебя учили математике, что даже с отображениями такая печальная картина?
S>Освежи определение отображения. В нем упоминается множество значений, которое определяется отображением. Никакие другие элементы, кроме как из области значений, отображение не должно связывать с областью определения.
если скажешь как это совмещается с возможностью фальсификации (с возможностью перепроверки) для лр-наблюдателя, тогда можно продолжить.
Здравствуйте, DarkGray, Вы писали:
S>>Освежи определение отображения. В нем упоминается множество значений, которое определяется отображением. Никакие другие элементы, кроме как из области значений, отображение не должно связывать с областью определения.
DG>если скажешь как это совмещается с возможностью фальсификации (с возможностью перепроверки) для лр-наблюдателя, тогда можно продолжить.
Безотносительно наблюдателя это напрямую связано с возможностью дальнейшего обсуждения чего-либо сложнее понятия отображения. Непонятно, что ты собрался фальсифицировать в определении отображения. Ведь никаких утверждений определение само по себе не дает.
S>Я думаю, что эту ветку дискуссии можно свернуть, т.к. мы упёрлись в предел некомпетентности. Я не могу вести серьёзную беседу с оппонентом, который вводит неработающие определения и отказывается это понимать.
отчасти это связано с тем, что на тебя влияет дурной пример samius-а, и ты вместо того, чтобы пытаться разобраться, что же утверждает собеседник, вешаешь ему ярлык — "глупый".
этот вопрос имеют посылку: утверждения собеседника — не имеют смысла. S> Я правильно понимаю, что для каждого примера применения функции F вы предлагаете отдельные варианты функции F?
альтернативный вопрос для посылки "утверждения собеседника — имеют смысл" мог быть: S_> У исходной функции было шареное состояние _a. Если функция восстанавливается как несколько функций, то как будет обеспечиваться шаринг состояния между этими функциями? S_> Может ли эта техника применяться для библиотек? или применимость ограничена только целыми программами? S_> Изначально была одна функция F, а вы предлагаете сделать ее как несколько. Минус — усложнение, а в чем плюс?
DG>при этом используется, что в реальных программах необходима однозначность значимой части результата, и что одновременно две функции F не исполняются
вопрос из предпосылки: сосебедник — дурак S> Вторая часть предположения S> а) слишком сильная, т.е. не основана ни на чём, кроме веры S>..
возможный альтернативный вопрос из предпосылки "есть смысл" S_> Вариант, когда удалось доказать, что к _a идет обращение только из функции F — понятен. а что делать в других случаях, когда не получилось это доказать? да, эти варианты редки, но они же тоже бывают в реальных программах.
S>А чем отличается библиотека от реальной программы?
для реальной программы можно сделать более точное предположение по статистике вызовов функций, использованных значений аргументов, трассам выполнения и т.д.
соответственно, для реальной программы можно шире использовать технику предварительных оптимизаций (в частности, если есть предположение, что вариант A вызывается в 4 раза чаще, чем вариант B, то ускорение варианта A в два раза, даже если это дало вынужденное замедление варианта B в два раза, дает общее ускорение на 60%)
и разделение одной функции на несколько вариантов делается как раз под такую технику. и разделение имеет смысл, если удалось выделить более часто используемую и более простую реализацию исходной функции.
S>Непонятно, что ты собрался фальсифицировать в определении отображения. Ведь никаких утверждений определение само по себе не дает.
есть (как минимум) два варианта как делать конструирование перебора множества:
1. можно сначала взять все функции F(Nat)->элемент множества, а потом выбрать из них ту, для которой доказано, что эта функция перебирает все элементы множества, что для сложных случаев будет нетривиально. при этом доказательство обязано быть полным, потому что если оно будет неполное, и ошибка все-таки просочиться и функция F все-таки какие-то элементы забывает, то это уже поймать нельзя будет.
2. можно идти от обратного: взять функции F'(элемент множества)->Nat и выбрать из них те, которые непротиворечивые (не переводят два элемента множества в одно число). здесь можно использовать неполные доказательства, потому что если ошибка все-таки есть и мы ее упустили при доказательстве, то она всплывает при исполнении.
и соответственно, второй вариант предпочтительнее
или другими словами: нельзя обеспечить, что не было ошибок, но можно обеспечить, чтобы ошибки (если они все-таки есть) были явные, вместо неявных.
Здравствуйте, DarkGray, Вы писали:
DG>и т.д.
Ну вот я попробовал разобраться в очень простом моменте — что предлагается в качестве "математического определения последовательности". Встал на точку зрения собеседника, прикинул, что может иметь смысл, скорректировал определение, чтобы не заниматься "ловлей на опечатках". В ответ — стена непонимания. Я привёл наглядный пример, показывающий, почему предложенное вами определение не работает и работать не может. В ответ — стена непонимания. То же самое мы имели со случаем "непрерывности времени" некоторое время назад. Чего вы от меня ещё хотите?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
DG>>из одного следует другое. можно лишь поговорить на тему: скольки элементам одного множества сколько элементов другого множества соответствует. S>Давайте поговорим. Вот вам отображение множества букв на множество натуральных чисел: A->>1 B->>1 C->>1 S>Какая последовательность задаётся этим отображением?
некорректная, если строго требуется однозначная последовательность
S>Вопрос повышенной сложности: зачем вы продолжаете в этом топике делать заведомо неверные утверждения, даже когда вас поправляют?
потому что они верные, если брать тот базис в котором они и утверждались.
ты же постоянно съезжаешь в свой базис, который достаточно противоречивый.
например, в данном случае ты используешь не имеющего научного смысла понятие "неверные утверждения".
с точки зрения научного подхода не бывает "неверных утверждений", а бывают "необоснованные", "неполные", "противоречивые" и т.д.
при этом слово "верные" можно использовать в дискуссии, если используется базис, что понятия автоматически непротиворечиво дополняется до утверждений, имеющих смысл. в данном случае, до научных терминов "необоснованные", "неполные" и "противоречивые".
и соответственно, есть два непротиворечивых базиса:
1. либо всегда формулируются обоснованные полные непротиворечивые утверждения в научных терминах, но тогда нельзя использовать утверждение "неверные утверждения".
2. либо утверждения автоматически дополняются, тогда ты должен был дополнить и мои утверждения очевидными выкладками.
DG>>если есть отображение множества на множество натуральных чисел, при этом одно натуральное число переходит в один элемент множества, то есть и функция перебора. перебирая натуральные числа перебираются и элементы исходного множества. S>В определении порядка таким образом нет никакой функции перебора. То, что её можно построить, в целом очевидно. Но вы-то делали утверждение, что последовательность в математике задаётся именно функцией перебора.
выделенное слово "именно" ты додумал сам.
я утверждал, что функции перебора достаточно, чтобы множество являлось последовательностью, и не утверждал, что это необходимо. слово "именно" является аналогом слова "необходимо", а не слова "достаточно".
также утверждаю, что для всякой последовательности можно построить(в математическом смысле, когда разрешается использовать бесконечные алгоритмы) функцию перебора элементов
вот это утверждение: либо не фальсифицируемо, либо подразумевает тривиальный ответ.
избегай, пожалуйста, тривиальных вопросов и переведи, пожалуйста, вопрос в фальсифицируемую плоскость — либо полноценным утверждением: "здесь можно применить вот такую формулировку такого-то определения, и данное утверждение противоречит выводу №5 из этого определения", либо частичным "а как это согласуется вот с такой-то формулировкой определения?"
S>>Ты определение отображения не забыл освежить?
DG>вот это утверждение: либо не фальсифицируемо, либо подразумевает тривиальный ответ.
DG>избегай, пожалуйста, тривиальных вопросов и переведи, пожалуйста, вопрос в фальсифицируемую плоскость — либо полноценным утверждением: "здесь можно применить вот такую формулировку такого-то определения, и данное утверждение противоречит выводу №5 из этого определения", либо частичным "а как это согласуется вот с такой-то формулировкой определения?"
Попробую:
DG>следующий вариант задает отображение с повторяющимися элементами
DG>
DG>F'(false) -> i, where 0<=i<=2
DG>F'(true) -> i, where 3 <= i < = 5
DG>
Описанная конструкция противоречит определению отображения, взятому, например, отсюда.
Утверждение о том что это задание отображения ложно.
Ок, хорошо, если вы хотели, чтобы отображение было сюрьективным, стоило так и написать, а не размазывать сопли на весь форум.
DG>тогда это определение противоречит определению многозначного отображения DG>
DG>Многозначное отображение — разновидность математического понятия отображения (функции).
Нет, не противоречит. Смотрите определение. Там просто область значений выбирается из 2^Y.
И если вам хотелось использовать многозначное отображение, то стоило об этом упомянуть в своём определении, т.к. по умолчанию отображения считаются однозначными.
Впрочем, остаётся загадкой главный вопрос: зачем вы занимаетесь умственным онанизмом вместо того, чтобы пользоваться готовыми определениями?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
A binary relation R is usually defined as an ordered triple (X, Y, G) where X and Y are arbitrary sets (or classes), and G is a subset of the Cartesian product X × Y. The sets X and Y are called the domain (or the set of departure) and codomain (or the set of destination), respectively, of the relation, and G is called its graph.
The statement (x,y) ∈ R is read "x is R-related to y", and is denoted by xRy or R(x,y). The latter notation corresponds to viewing R as the characteristic function on "X" x "Y" for the set of pairs of G.
The order of the elements in each pair of G is important: if a ≠ b, then aRb and bRa can be true or false, independently of each other.
то определение, которое ты привел соответствует подвиду отображений
functional (also called right-unique[1] or right-definite[citation needed]): for all x in X, and y and z in Y it holds that if xRy and xRz then y = z; such a binary relation is called a partial function.
зы
это как раз к теме, насколько ты свое толкование определений можешь считать эталонным. и насколько тот или иной авторитет (в частности коллективный в виде вики) можно считать эталонным.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, DarkGray, Вы писали:
DG>>тогда это определение противоречит определению многозначного отображения DG>>
DG>>Многозначное отображение — разновидность математического понятия отображения (функции).
S>Нет, не противоречит. Смотрите определение. Там просто область значений выбирается из 2^Y. S>И если вам хотелось использовать многозначное отображение, то стоило об этом упомянуть в своём определении, т.к. по умолчанию отображения считаются однозначными.
Да ничего бы не изменилось, т.к. элементом области значений многозначного отображения есть подмножество. И последовательность, определенная многозначным отображением есть последовательность подмножеств, которая записывается, например следующим образом:
Здравствуйте, samius, Вы писали:
S>Здравствуйте, Sinclair, Вы писали:
S>>Здравствуйте, DarkGray, Вы писали:
DG>>>тогда это определение противоречит определению многозначного отображения DG>>>
DG>>>Многозначное отображение — разновидность математического понятия отображения (функции).
S>>Нет, не противоречит. Смотрите определение. Там просто область значений выбирается из 2^Y. S>>И если вам хотелось использовать многозначное отображение, то стоило об этом упомянуть в своём определении, т.к. по умолчанию отображения считаются однозначными. S>Да ничего бы не изменилось, т.к. элементом области значений многозначного отображения есть подмножество. И последовательность, определенная многозначным отображением есть последовательность подмножеств, которая записывается, например следующим образом: S>
S>{ { 1 }, { 1, 2 }, { 1, 2, 3 }, ...}
S>
S>Речь-то явно не о таких последовательностях была.
В принципе, я вижу свет в конце тоннеля — если мы скажем, что бесконечной последовательностью является
сюрьективное многозначное отображение произвольного множества элементов на множество натуральных чисел,
а конечной последовательностью —
сюрьективное многозначное отображение произвольного множества элементов на множество индексов {i: i ∈ ℕ, i ≤ Length}
, то всё бы начало сходиться.
Но, во-первых, это определение сильно отличается от предложенного DG, а во-вторых, оно один хрен не совпадает с тем, чем пользуются все остальные люди.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали: DG>согласен был не прав, использовал слово "отображение" вместо термина "отношение". DG>значит во всем что было написано до этого, вместо слова "отображение" читать "отношение".
Не получится. Прямая подстановка даёт конструкции, у которых нет смысла на традиционном математическом языке. Вот смотрите:
формальное определение последовательности — это произвольное множество отображенное на множество натуральных чисел
Как тут заменить? Давайте возьмем высказывание, где хотя бы использована форма существительного:
я имел ввиду именно [отображение] отношение множества на натуральные числа
Нет такой конструкции — "отношение на". Парсер сломался.
Ну, давайте выбросим парсер и попробуем сконструировать что-то из того, что вы предлагаете. Есть, значит, некоторое множество X. Есть также и натуральные числа N.
Вроде бы есть какое-то отношение. По определению, отношение — это некоторое подмножество декартова произведения двух множеств. Надо полагать, это множества X и N.
Ок, вот мы задали некоторое отношение R в (X x N). Как нам из этого отношения получить последовательность?
На всякий случай напомню, что в последовательности очередной элемент должен определяться однозначным образом.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S>Ок, вот мы задали некоторое отношение R в (X x N). Как нам из этого отношения получить последовательность?
потребовать right-unique.
также необходимо, чтобы отношение было полным справа на всем множестве Nat(для бесконечных последовательностей) или на интервале (1..L), если это конечная последовательность.
при этом произвольное неполное справа right-unique отношение X x N можно дополнить (взаимооднозначным полным справа и полным слева на множестве для всех N, для которых есть образ в X) отношением N x N'. что даст отношение X x N', которое будет right-unique и полным справа. если это отношение обратить как N' x X, то оно будет слева полным и unique.
и соответственно последовательный перебор множества N' с использованием отношения N' x X — даст последовательность элементов множества X.
соответственно можно считать, что для произвольного отношения (X x N) преобразуемого в последовательность достаточно показать, что оно является right-unique. а необходимость полноты на N, и то, что требуется ввести дополнительное отношение N->N', если нет полноты — подразумевается по умолчанию
где сложные? вроде сплошные тривиальные выводы, которые элементарно восстанавливаются из контекста.
S> В то время как классическое определение не нуждается во всех этих уточнениях. Вопрос: зачем так извращаться, когда можно просто взять готовое определение и пользоваться им?
какое готовое? и как его использовать для моего утверждения, что если хочется записать сложную последовательность из всех элементов множества X в декларации программы, то:
лучше использовать F(X)->N (требование left-unique при этом автоматически подразумевается) для однозначных последовательностей (или F(X)->set<N> для последовательностей, где одни и те же элементы используются несколько раз) и использовать автоматическое восстановление F(N)->X из F(X)->N,
вместо того, чтобы задавать F(N)->X, а потом пытаться доказать, что эта функция полная справа.
Здравствуйте, DarkGray, Вы писали:
S>>И последовательность, определенная многозначным отображением есть последовательность подмножеств, которая записывается, например следующим образом:
DG>это странный вывод. DG>многозначное отображение X->Nat есть обычное отображение, которое можно отразить и получить Nat->X (при этом если X->Nat было right-unique, то Nat->X будет left-unique), то это даст последовательность.
Читаем в определении:
Многозначным отображением из множества X в Y называется всякое отображение F : X -> 2^Y, где 2^Y — совокупность всех подмножеств множества Y.
Заменяем Y на Nat, получаем:
Многозначным отображением из множества X в Nat называется всякое отображение F : X -> 2^Nat, где 2^Nat — совокупность всех подмножеств множества Nat.
Область значений многозначного отображения является множество. Никакой мистики нет.
Т.е. если ты рассмотришь функцию X -> 2^Nat, то она будет отображать элементы множества на множества.
Так можно записывать последовательность? Да. Но такая запись не является достаточно хорошей что бы определить последовательность. Например, возьмем следующее многозначное отображение Bool->Nat:
F'(false) -> {0, 1, 2}
F'(true) -> {2, 3, 4}
В нем ничего плохого нет. Но последовательность, построенная на таком отображении будет хромать на две ноги, т.к. на месте 2 должно быть два значения из Bool. Но все будет нормально, если определять последовательность подмножеств Bool.
Аккуратно только надо обращаться с элементами и называть вещи своими именами. Не можем мы раскрыть внутренние скобки и записать все подряд. Конечно сможем, но никакой связи такие последовательности иметь не будут.
DG>Свойство, чтобы в Nat не было дырок желательно, но не является необходимым. Nat с "дырками" можно еще раз отобразить уже в Nat без "дырок".
Как сказано в определении, областью значений является множество всех подмножеств, а не само множество.
DG>с точки зрения математики здесь всё корректно, а вот с точки зрения реальных алгоритмов уже не всегда ("затягивание" дырок может выйти за допустимое кол-во шагов)
С точки зрения математики все некорректно.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>В принципе, я вижу свет в конце тоннеля — если мы скажем, что бесконечной последовательностью является S>
S>сюрьективное многозначное отображение произвольного множества элементов на множество натуральных чисел,
S>а конечной последовательностью — S>
S>сюрьективное многозначное отображение произвольного множества элементов на множество индексов {i: i ∈ ℕ, i ≤ Length}
S>, то всё бы начало сходиться. S>Но, во-первых, это определение сильно отличается от предложенного DG, а во-вторых, оно один хрен не совпадает с тем, чем пользуются все остальные люди.
Кажется я понял, свет действительно там проблескивает. Только больно сложно оперировать таким определением, если надстроить еще пару этажей (например начать обсуждать сходимость такой конструкции), то свет потухнет. Во всяком случае, давать такую хрень в первом семестре будет равноценно геноциду.
Здравствуйте, igna, Вы писали:
I>В статьях про "Immutable object" или про "Неизменяемый объект" в Википедии, во всех примерах речь идет о типах, все экземпляры которых неизменяемы, хотя согласно определениям данным в начале статей i в примере ниже является неизменяемым объектом:
I>
I>int const i = 123;
I>
I>Так ли это, можно ли назвать i здесь immutable?
Любой объект в программе который ты намеренно не будешь изменять — будет неизменяемым объектом!
S> Да. Но такая запись не является достаточно хорошей что бы определить последовательность.
согласен. и это есть хорошо , если происходить специфицирование в понимании двойственности: что то, что мы считаем хорошим, не всегда является хорошим на самом деле.
если специфицировать F(X)->N, то происходит несколько автоматических перепроверок корректности спецификации.
если специфицировать F(N)->X, то вся корректность держится на единственном доказательстве, что эта функция полная справа.
соответственно, первое задание более устойчивое — ряд ошибок автоматически выявляются на более поздних этапах, второе задание — неустойчивое, допущенная ошибка больше никогда не проявляется, и лишь скрыто пакостит.
S>> Да. Но такая запись не является достаточно хорошей что бы определить последовательность.
DG>согласен. и это есть хорошо , если происходить специфицирование в понимании двойственности: что то, что мы считаем хорошим, не всегда является хорошим на самом деле. DG>если специфицировать F(X)->N, то происходит несколько автоматических перепроверок корректности спецификации.
И добавляются новые ошибки, более критичные к возможности построения последовательности.
DG>если специфицировать F(N)->X, то вся корректность держится на единственном доказательстве, что эта функция полная справа.
Последовательность, заданная такой функцией будет корректна в любом случае, вне зависимости от свойств функции. А что до дополнительных свойств этой последовательности — так это дело десятое.
DG>соответственно, первое задание более устойчивое — ряд ошибок автоматически выявляются на более поздних этапах, второе задание — неустойчивое, допущенная ошибка больше никогда не проявляется, и лишь скрыто пакостит.
Первое задание не всегда корректное. Второе — всегда.
DG>>соответственно, первое задание более устойчивое — ряд ошибок автоматически выявляются на более поздних этапах, второе задание — неустойчивое, допущенная ошибка больше никогда не проявляется, и лишь скрыто пакостит. S>Первое задание не всегда корректное. Второе — всегда.
корректность того, что все элементы исходной последовательности X перебираются в результате последовательности — волнует больше, чем корректность работы самой последовательности.
в частности в задачах обеспечения безопасности, надежности и т.д., т.к. понятно как можно защититься от некорректной последовательности, но не понятно как защитится от некорректности полноты перебора.
DG>>>соответственно, первое задание более устойчивое — ряд ошибок автоматически выявляются на более поздних этапах, второе задание — неустойчивое, допущенная ошибка больше никогда не проявляется, и лишь скрыто пакостит. S>>Первое задание не всегда корректное. Второе — всегда.
DG>корректность того, что все элементы исходной последовательности X перебираются в результате последовательности — волнует больше, чем корректность работы самой последовательности. DG>в частности в задачах обеспечения безопасности, надежности и т.д., т.к. понятно как можно защититься от некорректной последовательности, но не понятно как защитится от некорректности полноты перебора.
Если последовательность некорректна, о каких пробежках вообще речь? Нет последовательности = нет пробежек по ней.
{ 1, 2, (3 или 4 ?), ...)
Ну и как тут доказывать что все элементы перебраны? 3 перебрали? А 4?
S>>Если последовательность некорректна, о каких пробежках вообще речь? Нет последовательности = нет пробежек по ней.
DG>наткнулись на ошибку — ее исправили, и побежали дальше (заново) DG>а в другом случае — даже натыкаться не на что.
В первом случае будет проще лишь для конечных X (а значит и длина последовательности будет конечной при задании через F::X->Nat). В аналогичном случае проверка полноты покрытия при определении через F::Nat->X будет ничуть не сложнее.
Если X хотя бы счетно, то первый случай ничем не лучше.
S>Итак, библиотека от реальной программы не отличается ничем.
с основной мыслью твоей согласен, но часть выводов считаю неполными.
остановлюсь на ряде моментов..
сначала небольшое отступление, что такое понятия, как они используются и какой они смысл несут...
понятия появляются как краткое обозначение распространенных ролей использования:
понятие "чайник" может обозначать роль "чайник" — эту роль имеет предмет, в котором готовят воду для чая,
понятие "стол" может обозначать роль "стол" — эту роль имеет предмет, на поверхности которого человек выполняет определенную деятельность,
понятие "программная библиотека" может обозначать роль "програмная библиотека" — эту роль имеет код, который используется другой программой
понятие "декларативная программа" может обозначать роль "декларативная программа" — эту роль имеет код, который позволяет понять, что будет сделано, без выполнения кода.
понятие "чайник" может обозначать объект "чайник" — это предмет, который заточен под преимущественное выполнение роли "чайник"
или в общем виде:
понятие X может обозначать объект X — это предмет, который заточен под преимущественное выполнение роли X.
при этом у такого объекта начинают появляться свойства, которые упрощают использование объекта в роли X.
у объекта "чайник" появляется носик, ручка, крышка и т.д., которые упрощают использование в роли "чайник", в частности, носик упрощает наливание воды в кружку.
у объекта "стол" появляется место для ног под поверхностью, чтобы было удобно сидеть.
у объекта "программная библиотека" появляется программное метаописание, возможность связываться с библиотекой напрямую в памяти и т.д.
у объекта "декларативная программа" появляется близость к логической нотации, требования иммутабельности и т.д.
понятия могут использовать как классы, и тогда подразумевается, что объект принадлежащий одному классу не может принадлежать другому классу.
например, для класса "чайник" подразумевается, что он непересекается с классами "кастрюля", "котелок", "термос", "кружка" и т.д.
класс "стол" непересекается с классом "стул", "тумбочка", "подоконник" и т.д.
класс "программная библиотека" непересекается с классом "программа".
класс "декларативная программа" непересекается с классом "императивная программа".
непротиворечивое деление объектов на такие классы можно сделать только для объектов, которые специализируется на выполнение одной роли, и только пока они выполняют только эту роль.
например, термопот (который одновременно предназначен, и для роли чайник, и для роли термос) или чайник, в котором студенты варят пельмени — уже тяжело однозначно и непротиворечиво классифицировать как чайник, термос или кастрюля.
можно продолжать классифицировать по исходным классам и неоднофункциональные объекты, но здесь уже классификация будет плавать от задачи к задаче, от одной точки зрения к другой точке зрения и т.д.
при этом в каждой конкретной задаче необходимо явно определить, о чем идет речь: о ролях, об объектах, и какие свойства необходимы, чтобы объект входил в класс X.
от рассмотрения отдельных задач можно перейти к рассмотрению классов задач, и здесь уже удобно будет ввести аппарат нечетких множеств http://ru.wikipedia.org/wiki/%D0%9D%D0%B5%D1%87%D1%91%D1%82%D0%BA%D0%BE%D0%B5_%D0%BC%D0%BD%D0%BE%D0%B6%D0%B5%D1%81%D1%82%D0%B2%D0%BE.
и зафиксировать, что степень отнесение объекта к нечеткому множеству "чайник" показывает насколько объект похож на классический чайник, и показывает в насколько широком классе задач можно считать, что этот объект есть "чайник".
из-за того, что метрику похожести и метрику подсчета отношения кол-ва задач в определенном классе задач ко всему множеству задач — можно брать произвольные, это и будет давать нечеткие множества: термопот сильно похож на чайник, т.к. включает большинство свойств чайника, и средне похож на термос, потому что такая вспомогательная функция, как мобильность, слабо поддержана.
при этом можно продолжать работать и в четких определениях, а нечеткие определения, утверждения и классификация использовать как направление, с которого начинается четкое специфицирование.
при этом переиспользование терминов делается для того, чтобы облегчить вхождение людей в задачу.
человеку проще представить один раз нечеткий класс "чайник" и восстанавливать его до четкого определения в каждой задаче, чем переключаться между четкими классами "Ч381 дробь 137 бис", "Ч53 штрих дробь 2" и т.д.
S>Итак, библиотека от реальной программы не отличается ничем.
как именно ты в данном случае рассматриваешь эти понятия? как роли? как однофункциональные объекты? как непересекающиеся классы? как нечеткие классы?
твое утверждение близко к последнему рассмотрению "нечеткие классы", и к задаче — в какой роли конкретный код может использоваться.
и при этом твое утверждение лучше переформулировать как грань: между библиотекой и реальной программой очень нечеткая. объект "программа" может легко может выступать в роли "библиотека" (например, когда некая программа использует word для обработки doc-файлов), или объект "библиотека" может использоваться в роли "программа" (например, asp.net сайт, который выпускается в виде библиотеки, но для пользователя, выступает как отдельная программа)
при этом для задачи "спецификация результата" классы "программа" и "библиотека" при классификации объектов можно определить как:
программа: внешняя граница кода — это только ввод/вывод (консоль, файлы, gui, socket-ы и т.д.)
программная библиотека: внешняя граница — только все публичные члены всех публичных классов (и отсутствие ввода-вывода).
таких чистых программ и библиотек почти не бывает, поэтому введем метрику отношения к тому или иному классу как процент function point приходится на ввод-вывод и функции уровня ЯП. 0% ввода-вывода — библиотека, 100% — программа.
классы "программа" и "библиотека" при классификации ролей можно определить как нечеткие множества с двумя чистыми крайностями:
программа — из всего кода реально используется одна функциональная точка с одним и тем же значением аргументов
библиотека — из всего кода реально используется все 100% функциональных точек на всем множестве аргументов.
общую метрику Z для объекта "программа/библиотека" выступающего в роли "программы/библиотеки" — можно задать, как, например, перемножение одного другого.
метрика Z корреллирует с трудностью восстановления спецификации результата. чем выше значение, тем выше вероятность, что спецификация результата будет совпадать с самим кодом.
S>В первом случае будет проще лишь для конечных X (а значит и длина последовательности будет конечной при задании через F::X->Nat). В аналогичном случае проверка полноты покрытия при определении через F::Nat->X будет ничуть не сложнее. S>Если X хотя бы счетно, то первый случай ничем не лучше.
сходу не вижу, как это можно использовать для проверки последовательности заданной как (вырожденный случай paging-а со страницей из одного элемента):
вот что здесь надо потребовать, чтобы эта функция корректно перебирала все элементы, и что делать если в реальности эти требования не возможно выполнить?
с помощью какого алгоритма такие требования можно выделить?
Здравствуйте, DarkGray, Вы писали:
S>>В первом случае будет проще лишь для конечных X (а значит и длина последовательности будет конечной при задании через F::X->Nat). В аналогичном случае проверка полноты покрытия при определении через F::Nat->X будет ничуть не сложнее. S>>Если X хотя бы счетно, то первый случай ничем не лучше.
DG>сходу не вижу, как это можно использовать для проверки последовательности заданной как (вырожденный случай paging-а со страницей из одного элемента): DG>
Твоя F(i) это не отображение. Аппелирую к определению отображения(функции). Каждому i нужно сопоставить один конкретный элемент из множества. В твоей F(i) нет детерминированности, значит речи о последовательности нет. Хочешь проверять его свойства — вперед. Честно говоря, не понимаю, как это у тебя получится лучше с функцией Items->N.
DG>вот что здесь надо потребовать, чтобы эта функция корректно перебирала все элементы, и что делать если в реальности эти требования не возможно выполнить? DG>с помощью какого алгоритма такие требования можно выделить?
Хочешь продолжить разговор о последовательностях — приведи пример с последовательностью. Можем рассмотреть в качестве последовательности набор элементов, выбранных с помощью F(i) и зафиксированных после этого выбора. Только F(i) в таком продолжении будет за бортом.
Здравствуйте, DarkGray, Вы писали:
S>>Итак, библиотека от реальной программы не отличается ничем. DG>как именно ты в данном случае рассматриваешь эти понятия? как роли? как однофункциональные объекты? как непересекающиеся классы? как нечеткие классы?
Я продемонстрировал, как я рассматриваю понятия библиотеки и программы. В вашей классификации — это рассмотрение с точки зрения функциональных ролей, попытка формализовать трактовку "реальной программы" как того, чем пользуется пользователь, и "библиотеки" как того, чем пользуются программы.
DG>таких чистых программ и библиотек почти не бывает, поэтому введем метрику отношения к тому или иному классу как процент function point приходится на ввод-вывод и функции уровня ЯП. 0% ввода-вывода — библиотека, 100% — программа.
Я ведь знал, что вам захочется ввести метрику. И я предупреждал, что вы упаритесь вводить её мало-мальски непротиворечивым способом.
Вот и это определение метрики никуда не годится. Посчитайте процент function point в программе grep.
DG>метрика Z корреллирует с трудностью восстановления спецификации результата. чем выше значение, тем выше вероятность, что спецификация результата будет совпадать с самим кодом.
Гуманитарщина. Т.е. наукообразные рассуждения ни о чём.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
S> И я предупреждал, что вы упаритесь вводить её мало-мальски непротиворечивым способом.
во-первых, то что ты сейчас требуешь называется однозначность, а не непротиворечивость.
во-вторых, любое фиксирование(декларирования, измерения и т.д.) делается ради цели (появление возможности делать доп. выводы, передача образа от одного человека другому и т.д.)
ради какой цели ты сейчас хочешь однозначно зафиксировать метрику?
S>Вот вам другое утверждение: "если хочется записать сложную последовательность из всех элементов множества X без повторений в декларации программы, то лучше задать на этом множестве отношение строгого полного порядка, чем любые приседания с многозначными отображениями".
утверждение неверное для случаев, когда понятие "лучше" включает в себя критерии:
1. "требует меньше вычислительных ресурсов для достоверной проверки своей корректности",
2. "накладывает меньше ограничений на применимость"
Здравствуйте, DarkGray, Вы писали:
DG>во-первых, то что ты сейчас требуешь называется однозначность, а не непротиворечивость.
Непротиворечивость. Это когда у нас результат вычисления метрики не противоречит нашим ожиданиям. Например, будет забавно, когда библиотека для логгирования окажется "менее библиотечной", чем программа для разводки печатных плат.
DG>во-вторых, любое фиксирование(декларирования, измерения и т.д.) делается ради цели (появление возможности делать доп. выводы, передача образа от одного человека другому и т.д.) DG>ради какой цели ты сейчас хочешь однозначно зафиксировать метрику?
Я — не хочу. Это вам очень хочется вводить метрики на неизмеримых вещах.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, DarkGray, Вы писали:
S>>Вот вам другое утверждение: "если хочется записать сложную последовательность из всех элементов множества X без повторений в декларации программы, то лучше задать на этом множестве отношение строгого полного порядка, чем любые приседания с многозначными отображениями".
DG>утверждение неверное для случаев, когда понятие "лучше" включает в себя критерии: DG>1. "требует меньше вычислительных ресурсов для достоверной проверки своей корректности", DG>2. "накладывает меньше ограничений на применимость"
Вы заблуждаетесь.
1. Вычислительных ресурсов нужно ровно O(N), где N — длина последовательности.
2. Ограничений на применимость вовсе нет.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
V>>>>Зачем же от ленивости-то? Я сейчас с удовольствием почитал собственный аргумент, но в твоей озвучке. Итак... если нет возможности ощутить как-либо побочный эффект, он есть, или его нет? S>>>Смотри определение
V>>Не в Вики случайно? S>Да я там его смотрел. У тебя есть свое, лучше?
Конечно есть лучше. Например от нашего коллеги Синклера: побочные эффекты — это неявные зависимости. (Хотя на сегодня уже лучше оперировать понятием прозрачности ссылок, ИМХО).
А определение в Вики — это выхолощенная малопоследовательная в рассуждениях каша, сорри, которая родилась как некий собирательный ответ на объективные возражения относительно первоначального определения побочных эффектов. Попробуй дать ты своими словами, только без вот этих компрометирующих всю затею частностей, типа упоминания операций ввода-вывода в том определении, которое должно претендовать на общность и универсальность.
V>>Да запусти любую программу на хаскеле, да посмотри. S>Проблема в том, что результат выполнения main на хаскеле (без использования бэкдоров) является функцией, ну или его можно воспринимать как фукнцию. И увидеть побочный эффект от выполнения main я затрудняюсь. А с тем что эта функция (результат main) может иметь побочные эффекты, я не спорю.
Дык, давай тогда с тем же успехом рассматривать в С++ только шаблоны, порождающие целевой код. А что... очень "чистый" язык получается...
Кароч, с таким подходом, "тут смотрим, тут не смотрим" мы далеко не уедем. Речь идет о целевой исполняемой программе. То, что в Хаскеле некая часть кода безусловна чиста не говорит о том, что чист язык целиком, если рассматривать программу целиком. В С++ тоже часть кода обычно чиста, речь может идти лишь о гарантиях чистоты. И то, после моих замечаний относительно мощности современных компиляторов, вот эти условные визуальные и объятные человеческим разумом гарантии выглядят малость жалко и являются попыткой извратить смысл происходящего, т.е. натянуть происходящее на аналогию исполнения программы у нас в голове, а не современных компах.
V>>Мои рассуждения в пред. посте применимы к технике ООП, ведь если объект не имеет зависимостей от глобальных данных, то любые вызовы его методов в однопоточном апартаменте сводятся к эквивалентным чистым S>Чушь!
Вот, ЧТД. Не подумав. А ведь именно так реализовано ФП "унутре" на современных архитектурах.
S>Возьмем пример DarkGray-а, где создается объект C, который не зависит ни от каких глобальных данных (напрямую). Но зависит от GetTickCount, который seed в rnd, что данными назвать затруднительно. Тем не менее, считать такой объект чистым — весьма наивно. S>Да, пусть объект C имеет зависимость от rnd лишь в конструкторе. Но эта зависимость могла бы быть в методе. И эта зависимость не от данных. Имей в виду, когда будешь карежить определения в другой раз.
Я имею. Мы вообще декларативность обсуждали, а на побочные эффекты съехали из-за этого недоразумения:
While functional languages typically do appear to specify "how", a compiler for a purely functional programming language is free to extensively rewrite the operational behavior of a function, so long as the same result is returned for the same inputs. This can be used to, for example, make a function compute its result in parallel, or to perform substantial optimizations (such as deforestation) that a compiler may not be able to safely apply to a language with side effects.
Характерно, что я еще помню те времена, когда декларативным считали не функциональный подход (бо он такой же низкоуровневый как ООП или даже еще ниже, из-за плохой инкапсуляции), а некие высокоуровневые языки программирования или DSL, в которых невозможно было постановку задачи (т.е. исходник) перепутать с "что" на "как". Самые яркие представители — это Пролог и SELECT в SQL.
Вот это новое определение насчет приписывания ФП в декларативные языки появилось относительно недавно и сразу же успело устареть. Я уже делал замечание, что компилятор в состоянии выводить зависимости, поэтому по-факту мы не видим функциональных языков, компиляторы которых выполняют все эти предполагаемые преобразования кода лучше, чем компиляторы того же С++, которые на основе полного анализа кода и вывода всех зависимостей делают все эти перечисленные преобразования на сегодня лучше всех остальных компилторов вместе взятых. Т.е. все эти техники: перестановку кода, спекулятивные вычисления во время компиляции, преобразования выражений и т.д. и т.п., т.е. те преобразования, которые якобы характерны только для ФП. В общем, по факту тот самый аргумент, за счет которого ФП некоторое время пытаются приписывать декларативному программированию не выдерживает никакой критики — действительность опровергает такой поверхностный подход.
И да, пока что компиляторы С++ не занимаются автоматическим распараллеливанием (на всякий случай дабы избежать лишних итераций обсуждения относительно одной неиспользуемой таки техники), но это не от того, что они неспособны вывести все зависимости... они-то их выводят замечательно, я предлагаю поверить на слово человеку, который много изучает генерируемый ассемблерный код, особенно в местах, где происходят интенсивные вычисления... Просто по сегодняшним реалиям создание дополнительных потоков и синхронизация их результатов в конце суммарно очень дорогие, чтобы поручать это компилятору (особенно когда все вычисления происходят в таком режиме). Не всегда овчинка стоит выделки, во время компиляции ты этого не узнаешь ни на какой технике, на на ФП ни на ООП, это определяется только во время профилирования/тестов. Пусть лучше это происходит с помощью специальных либ, типа PLINQ которые программист использует под свою ответственность.
S>>>Теперь по поводу, нельзя ли выкидывать сразу копию... Копию выкидывать сразу можно при определенных условиях. Но это трюк вычислителя, а не языка программирования. Из того что копия может быть выкинута вычислителем, не следует ровно ничего в отношении императивности языка, описывающего порождение копии.
V>>Нет, из этого следует детерминированность, а только она и является целью, а вовсе не абстрактная "чистота". S>Напоминаю о примере с якобы детерминированным printf-ом. Детерминированности недостаточно для изменения порядка.
Понимаешь... заданный порядок доступа к любому ресурсу можно получить только из одного потока, либо через явную синхронизацию, что есть аналог однопоточности для ресурса, коль разные потоки обращаются к нему строго по-очереди. И в этом плане мы уже обсудили достаточно относительно того, как заданный порядок обращений к ресурсу обеспечить в императиве или в ФП (через явное задание вложенности ф-ий, например). А коль разделяемый ресурс используется из произвольных потоков, то и картинка на нем произвольная. Ключевое здесь "разделяемый" — вот где более фундаментальный водораздел м/у подходами к программированию, чем ФП vs императив, бо в случае локальных зависимостей для императива (или выводимости этой зависимости через мощщи современных компиляторов) обе техники ведут себя одинаково. А в случае необходимости доступа к разделяемому ресурсу, увы, обе техники тоже ведут себя одинаково, обеспечивая некий обязательный порядок операций обращений к такому ресурсу (IO в Хаскеле мы уже обсуждали).
Вот и получается, что (А) обе техники ФП и императив программируют в стиле "как" (даже Вики с этим согласна), (B) для случая обращения к локальным и нелокальным ресурсам обе техники тоже ведут себя одинаково на современных компиляторах, (C) отличаются только тем, что в ФП (например в Хаскеле) чистота вносится в контракт для обеспечения явности зависимостей, а в императиве зависимости выводятся компилятором (ИМХО, в ФП тоже нечистые места могли бы выводиться автоматически, вряд ли сложно доработать Хаскель до этой фичи), т.е. обоим техникам в итоге доступны преобразования, которые по мнению Вики рассматривают программу ФП в терминах "как" в кач-ве "что".
Вот и получается, что разницы толком никакой, она сугубо в голове, т.е. в фанатизме и ангажированности, от непонимания, как всё устроено и работает. Разумеется, современная императивная программа на С++ столь же декларативна и даже еще больше, чем эквивалентная программа на любом ФП, бо компиляторы С++ на сегодня больше всех остальных компиляторов абстрагируют исходный код от конечного результата, используя его лишь как некую отправную декларативную точку для череды серьезных преобразований с учетом всех обнаруженных компилятором зависимостей.
==============
Сорри, на другие ветки отвечать не буду, у нас там пошло много повторений, к сожалению.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
V>>>>>... если нет возможности ощутить как-либо побочный эффект, он есть, или его нет? V>>>Не в Вики случайно? S>>Да я там его смотрел. У тебя есть свое, лучше?
V>Конечно есть лучше. Например от нашего коллеги Синклера: побочные эффекты — это неявные зависимости.
Это не определение, это пояснение, выдранное из контекста. V>(Хотя на сегодня уже лучше оперировать понятием прозрачности ссылок, ИМХО).
Вообще говоря, побочный эффект и ссылочная прозрачность — это довольно разные вещи, и подменять одно другим несколько наивно, ИМХО.
V>А определение в Вики — это выхолощенная малопоследовательная в рассуждениях каша, сорри, которая родилась как некий собирательный ответ на объективные возражения относительно первоначального определения побочных эффектов. Попробуй дать ты своими словами, только без вот этих компрометирующих всю затею частностей, типа упоминания операций ввода-вывода в том определении, которое должно претендовать на общность и универсальность.
Ты об этом определении?
In computer science, a function or expression is said to have a side effect if, in addition to returning a value, it also modifies some state or has an observable interaction with calling functions or the outside world.
Мне оно нравится. Конечно, если ты мне подскажешь как общно и универсально выразить "изменение некоторого состояния" и "обозримое взаимодействие с внешним (по отношению к функции) миром", то я попробую переформулировать.
S>>Проблема в том, что результат выполнения main на хаскеле (без использования бэкдоров) является функцией, ну или его можно воспринимать как фукнцию. И увидеть побочный эффект от выполнения main я затрудняюсь. А с тем что эта функция (результат main) может иметь побочные эффекты, я не спорю.
V>Дык, давай тогда с тем же успехом рассматривать в С++ только шаблоны, порождающие целевой код. А что... очень "чистый" язык получается...
Шаблоны шаблонам рознь. И код на шаблонах вполне может быть декларативным, коль не изменяет состояние. А может быть и нет. Но код не будет декларативным только лишь потому что ты приписал к нему template<class X>. Если функция плодила побочные эффекты, то она их и будет плодить, даже будь записанной в виде шаблона. V>Кароч, с таким подходом, "тут смотрим, тут не смотрим" мы далеко не уедем. Речь идет о целевой исполняемой программе. То, что в Хаскеле некая часть кода безусловна чиста не говорит о том, что чист язык целиком, если рассматривать программу целиком. В С++ тоже часть кода обычно чиста, речь может идти лишь о гарантиях чистоты. И то, после моих замечаний относительно мощности современных компиляторов, вот эти условные визуальные и объятные человеческим разумом гарантии выглядят малость жалко и являются попыткой извратить смысл происходящего, т.е. натянуть происходящее на аналогию исполнения программы у нас в голове, а не современных компах.
Мощь компиляторов не имеет никакого отношения к определению декларативности подхода. Предлагаю к этому не возвращаться более.
V>>>Мои рассуждения в пред. посте применимы к технике ООП, ведь если объект не имеет зависимостей от глобальных данных, то любые вызовы его методов в однопоточном апартаменте сводятся к эквивалентным чистым S>>Чушь!
V>Вот, ЧТД. Не подумав. А ведь именно так реализовано ФП "унутре" на современных архитектурах.
Вот тебе пример:
class X {
public int Add(int a, int b) { Console.WriteLine(); return a + b; }
}
Зависимости от глобальных данных нет. Можешь свести вызов метода Add к эквивалентному чистому?
S>>Возьмем пример DarkGray-а, где создается объект C, который не зависит ни от каких глобальных данных (напрямую). Но зависит от GetTickCount, который seed в rnd, что данными назвать затруднительно. Тем не менее, считать такой объект чистым — весьма наивно. S>>Да, пусть объект C имеет зависимость от rnd лишь в конструкторе. Но эта зависимость могла бы быть в методе. И эта зависимость не от данных. Имей в виду, когда будешь карежить определения в другой раз.
V>Я имею. Мы вообще декларативность обсуждали, а на побочные эффекты съехали из-за этого недоразумения: V>
V>...This can be used to, for example, make a function compute its result in parallel, or to perform substantial optimizations (such as deforestation) that a compiler may not be able to safely apply to a language with side effects.
На побочные эффекты мы съехали вот почему:
declarative programming is a programming paradigm that expresses the logic of a computation without describing its control flow (control flow (or alternatively, flow of control) refers to the order in which the individual statements, instructions, or function calls of an imperative or a declarative program are executed or evaluated.)
V>Характерно, что я еще помню те времена, когда декларативным считали не функциональный подход
Извини, но я с тобой не могу согласиться даже в текущие времена. Поэтому, то что ты помнишь о тех временах, не является для меня аргументом.
V>Вот это новое определение насчет приписывания ФП в декларативные языки появилось относительно недавно и сразу же успело устареть. Я уже делал замечание, что компилятор..., компиляторы которых... компиляторы того же С++... лучше всех остальных компилторов вместе взятых ... во время компиляции. В общем, по факту тот самый аргумент, за счет которого ФП некоторое время пытаются приписывать декларативному программированию не выдерживает никакой критики — действительность опровергает такой поверхностный подход. V>пока что компиляторы С++ не занимаются автоматическим распараллеливанием ... чтобы поручать это компилятору... во время компиляции ты этого не узнаешь.
Я не считаю что компиляторы каким-то образом влияют на то, что называется декларативным подходом. Потому множественное упоминание компиляторов на мое мнение не повлияло.
Понимаешь, даже если код на хаскеле вместо компилятора хаскеля будет кем-то преобразован в дремучий императив на C++, а потом C++ его будет компилировать в коды, то исходный код на хаскеле будет все равно декларативен (конечно, если не будет использовать бэкдоры). Мне чихать, на то, кто компилит, как оптимизирует и распараллеливает. Пока мы говорим о парадигме, в которой записан код, это все значения не имеет. Да, некоторые хорошие свойства кода позволяют делать кое-что чуть лучше. Или не позволяют. Но это ПРИНЦИПИАЛЬНО другой этаж обсуждения.
Итого, сначала надо научиться отличать декларативный код от императивного, а потом уже говорить о возможностях компиляции и оптимизации. А ты опять заходишь с противоположного конца. Говоришь что компилируется все в один и тот же код, потому пофигу как написано.
S>>Напоминаю о примере с якобы детерминированным printf-ом. Детерминированности недостаточно для изменения порядка.
V>Понимаешь... заданный порядок доступа к любому ресурсу можно получить только из одного потока, либо через явную синхронизацию, что есть аналог однопоточности для ресурса, коль разные потоки обращаются к нему строго по-очереди. И в этом плане мы уже обсудили достаточно относительно того, как заданный порядок обращений к ресурсу обеспечить в императиве или в ФП (через явное задание вложенности ф-ий, например). А коль разделяемый ресурс используется из произвольных потоков, то и картинка на нем произвольная. Ключевое здесь "разделяемый" — вот где более фундаментальный водораздел м/у подходами к программированию, чем ФП vs императив, бо в случае локальных зависимостей для императива (или выводимости этой зависимости через мощщи современных компиляторов) обе техники ведут себя одинаково. А в случае необходимости доступа к разделяемому ресурсу, увы, обе техники тоже ведут себя одинаково, обеспечивая некий обязательный порядок операций обращений к такому ресурсу (IO в Хаскеле мы уже обсуждали).
Ты опять ушел куда-то на фронт. До потоков мы так и не дойдем, если не поймем что даже в одном потоке вызовы переставлять нельзя по причине побочных эффектов. ФП тут хорошо не тем, что оно позволяет явно выстроить последовательность без ";". А тем, что чистое ФП не оперирует побочными эффектами.
Т.е. если ты возьмешь ИП и скомпозируешь его функции дабы избежать";", то все равно ты будешь зависеть от порядка вычисления аргументов. В чистом ФП — нет.
V>Вот и получается, что (А) обе техники ФП и императив программируют в стиле "как" (даже Вики с этим согласна), (B) для случая обращения к локальным и нелокальным ресурсам обе техники тоже ведут себя одинаково на современных компиляторах, (C) отличаются только тем, что в ФП (например в Хаскеле) чистота вносится в контракт для обеспечения явности зависимостей, а в императиве зависимости выводятся компилятором (ИМХО, в ФП тоже нечистые места могли бы выводиться автоматически, вряд ли сложно доработать Хаскель до этой фичи), т.е. обоим техникам в итоге доступны преобразования, которые по мнению Вики рассматривают программу ФП в терминах "как" в кач-ве "что".
Забудь ты про компиляторы. main у хаскеля описывает свой результат. main в C++ описывает последовательность действий с побочными эффектами (кроме тривиального случая int main() { return 0;}). Разница в этом.
V>Вот и получается, что разницы толком никакой, она сугубо в голове, т.е. в фанатизме и ангажированности, от непонимания, как всё устроено и работает. Разумеется, современная императивная программа на С++ столь же декларативна и даже еще больше, чем эквивалентная программа на любом ФП, бо компиляторы С++ на сегодня больше всех остальных компиляторов абстрагируют исходный код от конечного результата, используя его лишь как некую отправную декларативную точку для череды серьезных преобразований с учетом всех обнаруженных компилятором зависимостей.
Разница тривиальна, меня удивляет почему ты не хочешь ее увидеть!
printf работает на побочный эффект. putString работает на свой результат и только на него, не производя побочного эффекта.
V>============== V>Сорри, на другие ветки отвечать не буду, у нас там пошло много повторений, к сожалению.
Не надо на другие ветки отвечать
Здравствуйте, samius, Вы писали:
V>>Конечно есть лучше. Например от нашего коллеги Синклера: побочные эффекты — это неявные зависимости. S>Это не определение, это пояснение, выдранное из контекста. V>>(Хотя на сегодня уже лучше оперировать понятием прозрачности ссылок, ИМХО). S>Вообще говоря, побочный эффект и ссылочная прозрачность — это довольно разные вещи, и подменять одно другим несколько наивно, ИМХО.
Ну, судя по данному тобой ниже определению, ты их с легкостью подменяешь. И таки это зависимые вещи, второе — лишь уточнение первого.
S>
In computer science, a function or expression is said to have a side effect if, in addition to returning a value, it also modifies some state or has an observable interaction with calling functions or the outside world.
S>Мне оно нравится. Конечно, если ты мне подскажешь как общно и универсально выразить "изменение некоторого состояния" и "обозримое взаимодействие с внешним (по отношению к функции) миром", то я попробую переформулировать.
ЧТД. Что есть "внешний мир"? Как именно он тебе доступен? Чаще всего через непрозрачные ссылки (хендлы и т.д.) Степень "внешнести" некоторого объекта — это степень прозрачности для нас его внутреннего устройства и ничего более... остальное — надуманно.
S>Мощь компиляторов не имеет никакого отношения к определению декларативности подхода. Предлагаю к этому не возвращаться более.
Имеет, предлагаю таки сначала аргументы, а потом, так и быть, не возвращаться. Напомню, что изначальный смысл термина "декларативность" это написание кода в духе "что", вместо "как". Остальное было притянуто за уши чуть позже и держится эта притянутость с большим трудом, я уже показал. А потому она держится с большим трудом, что программирование в ФП требует ничуть не меньших подробностей, чем в императивном ООП, например. А по остальным доводам, почему можно рассматривать код как "что" я уже высказывался неоднократно. Хотел бы или услышать возражения по существу аргумента, или не заходи на новый круг плиз. Просто, без аргументации, ты меня всё равно не уговоришь.
V>>Вот, ЧТД. Не подумав. А ведь именно так реализовано ФП "унутре" на современных архитектурах. S>Вот тебе пример: S>
S>class X {
S> public int Add(int a, int b) { Console.WriteLine(); return a + b; }
S>}
S>
S>Зависимости от глобальных данных нет. Можешь свести вызов метода Add к эквивалентному чистому?
Как это нет? Вызов WriteLine статический, то бишь оперирует некими глобальными данными, используемыми в этом вызове неявно.
V>>Я имею. Мы вообще декларативность обсуждали, а на побочные эффекты съехали из-за этого недоразумения: V>>
V>>...This can be used to, for example, make a function compute its result in parallel, or to perform substantial optimizations (such as deforestation) that a compiler may not be able to safely apply to a language with side effects.
S>На побочные эффекты мы съехали вот почему: S>
declarative programming is a programming paradigm that expresses the logic of a computation without describing its control flow (control flow (or alternatively, flow of control) refers to the order in which the individual statements, instructions, or function calls of an imperative or a declarative program are executed or evaluated.)
Я уже показал, что при вычислении компилятором всех зависимостей для императивного подхода мы получаем ровно тот же эффект, что и для ФП. Разница тут лишь в некоей дополнительной статической гарантии, в дополнительных признаках к типам (и сигнатурам), т.е. вот если IO не указано, что ты не можешь прочитать байт из памяти, потому что ссылка на байт идет тоже как IO. Это что-то вроде дополнительного признака, есть же дополнительные признаки типов в С++, например const и volatile.
V>>Характерно, что я еще помню те времена, когда декларативным считали не функциональный подход S>Извини, но я с тобой не могу согласиться даже в текущие времена. Поэтому, то что ты помнишь о тех временах, не является для меня аргументом.
Аргументы я как раз-таки привел. Ты в ответ постоянно повторяешь "не согласен". Оригинально спор проходит, однако...
V>>Вот это новое определение насчет приписывания ФП в декларативные языки появилось относительно недавно и сразу же успело устареть. Я уже делал замечание, что компилятор..., компиляторы которых... компиляторы того же С++... лучше всех остальных компилторов вместе взятых ... во время компиляции. В общем, по факту тот самый аргумент, за счет которого ФП некоторое время пытаются приписывать декларативному программированию не выдерживает никакой критики — действительность опровергает такой поверхностный подход. V>>пока что компиляторы С++ не занимаются автоматическим распараллеливанием ... чтобы поручать это компилятору... во время компиляции ты этого не узнаешь. S>Я не считаю что компиляторы каким-то образом влияют на то, что называется декларативным подходом. Потому множественное упоминание компиляторов на мое мнение не повлияло.
Давай уже по буквам разбирать то самое нововведение к определению декларативного подхода, которое я постоянно критикую. Итак, почему ФП отнесли к декларативному (мой корявый перевод):
Хотя функциональные языки, как правило, производят впечатление спецификаций (указаний)"как", компилятор для чисто функционального языка программирования имеет право значительно переписать поведение функции, до тех пор, пока возвращается тот же результат для тех же входных данных. Это может быть использовано, например, для преобразования вычислений в параллельный вид или для выполнения существенной оптимизации (например, упрощение), аналогичное компилятор не может безопасно применяться к языку с побочными эффектами.
Итак, де-фако это пояснение, почему ФП пытаются приписать декларативному, не выдерживает критики. Саму критику уже привел. Прошу спорить по-существу, если я ошибся в рассуждениях.
Предупреждаю сразу, что такие эфемерности как "взгляд на вещи" я обсуждать не собираюсь, сорри. Во-первых этими материями можно спекулировать до бесконечности, во-вторых, нет ни одной полностью "чистой" в ФП-смысле программы, которая бы делала хоть что-то полезное, кроме собственной компиллируемости. Это проза жизни из которой мы исходим. Повторять как работает ленивость в Хаскеле не надо, спасибо, все и так понимают. Так же как понимают и то, что вычисление оператора if, например, обязательно императивно даже в полностью чистых ф-иях, без IO. Императивно — это значит аргументы вычисляются во времени в строго известном порядке, заданном спецификацией языка. Именно поэтому эту "чистую" ф-ию if можно безопасно применять в IO-контексте, т.к. детерминировано ее поведение с т.з. последовательности ожидаемых побочных эффектов при вычислении операндов ф-ии if.
S>Понимаешь, даже если код на хаскеле вместо компилятора хаскеля будет кем-то преобразован в дремучий императив на C++, а потом C++ его будет компилировать в коды, то исходный код на хаскеле будет все равно декларативен (конечно, если не будет использовать бэкдоры).
Я не вижу, чем он будет более декларативен, чем аналогичный код на C++. Покажи, где декларативность. Чуть больше аннотаций к типам/сигнатурам в плане признака их чистоты?
S>Мне чихать, на то, кто компилит, как оптимизирует и распараллеливает. Пока мы говорим о парадигме, в которой записан код, это все значения не имеет.
Обычная такая функциональная парадигма, где надо писать с той же подробностью, а иногда и более подробно, чем в ООП. Всегда надо писать в терминах "как".
S>Итого, сначала надо научиться отличать декларативный код от императивного, а потом уже говорить о возможностях компиляции и оптимизации.
Имя, сестра, имя... Что же так слабо-то, а?
S>А ты опять заходишь с противоположного конца. Говоришь что компилируется все в один и тот же код, потому пофигу как написано.
Нет, я привел вполне конкретную критику вполне конкретного популярного определения. Не приписывай мне лишнего.
S>Ты опять ушел куда-то на фронт. До потоков мы так и не дойдем, если не поймем что даже в одном потоке вызовы переставлять нельзя по причине побочных эффектов. ФП тут хорошо не тем, что оно позволяет явно выстроить последовательность без ";". А тем, что чистое ФП не оперирует побочными эффектами.
Тебе то что? Не ты же вызовы переставляешь, а компилятор. Выходи до боли знакомое кино, которое тыщу раз видел от функциональщиков: то они призывают компилятор в свидетели, что ему, оказывается, можно порядки вызовов менять как угодно, то когда говорю, что в императивном языке компилятор может делать тоже самое, т.к. способен довольно глубоко просмотреть все зависимости и увидеть степень их "локальности" — то ай, стоп, не надо обсуждать компилятор... Сорри, это несерьезно.
Меня на самом деле интересует лишь кол-во описываемых подробностей в программе, а не то, каким образом компилятор будет колдовать над этим кодом в процессе его оптимизации. Вот что тебе с того, что компилятор способен там что-то менять в твоей программе без твоего ведома? Как это тебе помогает или мешает? Делая тоже самое для С++ компилятор не делает мне ни холодно ни жарко до тех пор, пока заданная мною семантика сохраняется. (Доп. быстродействие, конечно бонус, но оно пока не доступно функциональным языкам, несмотря на все эти обещанные вещи)
S>Т.е. если ты возьмешь ИП и скомпозируешь его функции дабы избежать";", то все равно ты будешь зависеть от порядка вычисления аргументов. В чистом ФП — нет.
Не я буду зависеть, а компилятор. А мне-то что? А компиятор тоже не особо ко мне прислушается... Вот ты в упор не понимаешь, что тебе пишут. компилятор как раз тоже сможет вычислять в произвольном порядке до тех пор пока способен установить отсутствие неявных зависимостей м/у аргументами.
Кароч давай ты сделаешь паузу и подумаешь, что же есть побочный эффект, для начала. Вот есть пара вычисляемых выражений-аргументов ф-ии. Предположим, что эта пара не пишет ничего во "внешний мир" в процессе своих вычислений. Так вот, возвращаясь к началу поста относительно побочных эффектов: если эти выражения имеют пересекающиеся зависимости, которые модифицируются в процессе вычисления, то порядок вычисления аргументов важен, если же не имеют — не важен. Точка. Вот почему определение побочных эффектов Синклера всяко грамотнее рассуждений о "внешнем мире", бо последнее нечетко и неграмотно.
S>Забудь ты про компиляторы. main у хаскеля описывает свой результат. main в C++ описывает последовательность действий с побочными эффектами (кроме тривиального случая int main() { return 0;}). Разница в этом.
Поправочка, main у Хаскеля описывает КАК ИМЕННО вычислить результат, что бы там кто ни говорил. И это описание в Хаскеле идет с ничуть не меньшими подробностями чем в каком-нить другом языке с уборкой мусора (не обязательно С++).
S>Разница тривиальна, меня удивляет почему ты не хочешь ее увидеть!
Если честно, я прекрасно понимаю т.з. оппонентов, твою например. Я просто надеялся выбить ответные аргументы, вместо слышимых по этому вопросу только лишь "не согласен, это другая т.з." и т.д. Бо противоречие в нынешних определениях налицо. А противоречие это возникло не на пустом месте, так всегда бывает, когда взятое изначально слово в кач-ве термина для обозначения похожих происходящих вещей потом пытается быть пересомтренным. И тогда вместо аксиоматичного понимания сути термина возникают поправки, толкования, объяснения и прочее чтобы показать, почему это некое знакомое слово используется в незнакомом качестве. По мне вся эта возня с насильственной мутацией терминов искуственна и притянута за уши, лучше было бы придумать другой термин, например для обсуждаемого подходит "прозрачность" или что-то в этом духе.
Здравствуйте, vdimas, Вы писали:
V>Здравствуйте, samius, Вы писали:
S>>Вообще говоря, побочный эффект и ссылочная прозрачность — это довольно разные вещи, и подменять одно другим несколько наивно, ИМХО.
V>Ну, судя по данному тобой ниже определению, ты их с легкостью подменяешь. И таки это зависимые вещи, второе — лишь уточнение первого.
Я их не могу путать просто потому что это вещи скорее противоположные, чем подменяемые. Если есть ссылочная прозрачность, значит побочный эффект не торчит наружу. Если торчит, значит прозрачности быть не может.
S>>
In computer science, a function or expression is said to have a side effect if, in addition to returning a value, it also modifies some state or has an observable interaction with calling functions or the outside world.
S>>Мне оно нравится. Конечно, если ты мне подскажешь как общно и универсально выразить "изменение некоторого состояния" и "обозримое взаимодействие с внешним (по отношению к функции) миром", то я попробую переформулировать.
V>ЧТД. Что есть "внешний мир"? Как именно он тебе доступен? Чаще всего через непрозрачные ссылки (хендлы и т.д.) Степень "внешнести" некоторого объекта — это степень прозрачности для нас его внутреннего устройства и ничего более... остальное — надуманно.
Это ты надумал. Если ты о ссылочной прозрачности, то нет никакой степени прозрачности. Либо прозрачно (абсолютно), либо нет и тоже абсолютно. Внешний мир по отношению к функции — это состояние программы. Если оно изменяется после вызова и это можно как-то обнаружить — значит функция имеет побочный эффект.
S>>Мощь компиляторов не имеет никакого отношения к определению декларативности подхода. Предлагаю к этому не возвращаться более.
V>Имеет, предлагаю таки сначала аргументы, а потом, так и быть, не возвращаться. Напомню, что изначальный смысл термина "декларативность" это написание кода в духе "что", вместо "как".
Вот в этом "что" вместо "как" где ты видишь место компилятора и его мощи?
V>Остальное было притянуто за уши чуть позже и держится эта притянутость с большим трудом, я уже показал.
Остальное тянешь ты — компиляторы, оптимизаторы, распараллеливатели, и даже уровень языка. V>А потому она держится с большим трудом, что программирование в ФП требует ничуть не меньших подробностей, чем в императивном ООП, например. А по остальным доводам, почему можно рассматривать код как "что" я уже высказывался неоднократно. Хотел бы или услышать возражения по существу аргумента, или не заходи на новый круг плиз. Просто, без аргументации, ты меня всё равно не уговоришь.
Я тоже высказывался неоднократно. Меня твои высказывания не очень убеждают, т.к. ты ходишь слишком далеко от определения декларативности. Тебя мои не убеждают. Значит надо завязывать.
Вот тут ты теперь привел число либо качество подробностей. А подробности не имеют отношения к декларативности, покуда это не подробности изменения состояния.
S>>Зависимости от глобальных данных нет. Можешь свести вызов метода Add к эквивалентному чистому?
V>Как это нет? Вызов WriteLine статический, то бишь оперирует некими глобальными данными, используемыми в этом вызове неявно.
Оперирует — да. Зависит — нет. Что бы уж совсем не зависело — можно проглотить исключения.
S>>На побочные эффекты мы съехали вот почему: S>>
declarative programming is a programming paradigm that expresses the logic of a computation without describing its control flow (control flow (or alternatively, flow of control) refers to the order in which the individual statements, instructions, or function calls of an imperative or a declarative program are executed or evaluated.)
V>Я уже показал, что при вычислении компилятором всех зависимостей для императивного подхода мы получаем ровно тот же эффект, что и для ФП. Разница тут лишь в некоей дополнительной статической гарантии, в дополнительных признаках к типам (и сигнатурам), т.е. вот если IO не указано, что ты не можешь прочитать байт из памяти, потому что ссылка на байт идет тоже как IO. Это что-то вроде дополнительного признака, есть же дополнительные признаки типов в С++, например const и volatile.
Опять ты аппелируешь к компилятору
И причем тут IO, если код с ним не может взаимодействовать без бэкдоров?
V>>>Характерно, что я еще помню те времена, когда декларативным считали не функциональный подход S>>Извини, но я с тобой не могу согласиться даже в текущие времена. Поэтому, то что ты помнишь о тех временах, не является для меня аргументом.
V>Аргументы я как раз-таки привел. Ты в ответ постоянно повторяешь "не согласен". Оригинально спор проходит, однако...
Ты в качестве аргументов привел уровень языка, качество преобразований компилятора... А тему, как это связано с определением декларативности, не раскрыл.
S>>Я не считаю что компиляторы каким-то образом влияют на то, что называется декларативным подходом. Потому множественное упоминание компиляторов на мое мнение не повлияло.
V>Давай уже по буквам разбирать то самое нововведение к определению декларативного подхода, которое я постоянно критикую.
То что ты критикуешь, к сожалению, к определению декларативного подхода никак не относится. V>Итак, почему ФП отнесли к декларативному (мой корявый перевод):
Ты тут уже сделал кучу заблуждений. Не всякий код на ФП декларативен, как не всякий код на ИП императивен. С чего ты сразу всё ФП подписал к декларативному-то? V>
V>Хотя функциональные языки, как правило, производят впечатление спецификаций (указаний)"как"
Всё. Больше в этой цитате обсуждать нечего.
V>Итак, де-фако это пояснение, почему ФП пытаются приписать декларативному, не выдерживает критики.
Де-факто это не пояснение "почему", де-факто это свойства, которые вытекают из детерминированности и чистоты. Местами эти оптимизации можно применять и к ИП коду, но только пока сайд-эффекты не перепутываются. V>Саму критику уже привел. Прошу спорить по-существу, если я ошибся в рассуждениях.
Еще раз, ты критикуешь следствия декларативности, ссылаясь на то что компиляторы могут делать те же трюки с императивным кодом. А о том что они это могут делать только в ограничениях влияния сайд-эффектов, ты как-то внимание не акцентируешь.
V>Предупреждаю сразу, что такие эфемерности как "взгляд на вещи" я обсуждать не собираюсь, сорри. Во-первых этими материями можно спекулировать до бесконечности, во-вторых, нет ни одной полностью "чистой" в ФП-смысле программы, которая бы делала хоть что-то полезное, кроме собственной компиллируемости. Это проза жизни из которой мы исходим. Повторять как работает ленивость в Хаскеле не надо, спасибо, все и так понимают.
Нет, не все, но повторять уже задолбало. V>Так же как понимают и то, что вычисление оператора if, например, обязательно императивно даже в полностью чистых ф-иях, без IO.
даже SELECT в SQL будет выполнен императивно. Даже матчинг регекса будет выполнен имеративно. Однако, какое это отношение имеет к декларативности SELECT-а и регекса?
V>Императивно — это значит аргументы вычисляются во времени в строго известном порядке, заданном спецификацией языка. Именно поэтому эту "чистую" ф-ию if можно безопасно применять в IO-контексте, т.к. детерминировано ее поведение с т.з. последовательности ожидаемых побочных эффектов при вычислении операндов ф-ии if.
Никаких побочных эффектов при вычислении if нет, т.к. ничего кроме вычисления условия в нем не происходит. Если настаиваешь на обратном — попрошу продемонстрировать побочные эффекты от вычисления if.
S>>Понимаешь, даже если код на хаскеле вместо компилятора хаскеля будет кем-то преобразован в дремучий императив на C++, а потом C++ его будет компилировать в коды, то исходный код на хаскеле будет все равно декларативен (конечно, если не будет использовать бэкдоры).
V>Я не вижу, чем он будет более декларативен, чем аналогичный код на C++. Покажи, где декларативность. Чуть больше аннотаций к типам/сигнатурам в плане признака их чистоты?
Какой "покажи", если мы даже с printf разобраться не можем? А теперь и с if-ом
S>>Мне чихать, на то, кто компилит, как оптимизирует и распараллеливает. Пока мы говорим о парадигме, в которой записан код, это все значения не имеет.
V>Обычная такая функциональная парадигма, где надо писать с той же подробностью, а иногда и более подробно, чем в ООП. Всегда надо писать в терминах "как".
Подробно != "как". Хотя тут можно и путать даже на бытовом уровне. Вопрос "как ты любишь кофе" провоцирует ответы как декларативные, так и императивные. Причем, декларативный ответ может содержать больше подробностей, чем императивный.
V>Имя, сестра, имя... Что же так слабо-то, а?
Бэкингем
А кроме шуток — я не знаю как с тобой изъясняться, если у тебя хаскелевский if обладает побочными эффектами
S>>А ты опять заходишь с противоположного конца. Говоришь что компилируется все в один и тот же код, потому пофигу как написано.
V>Нет, я привел вполне конкретную критику вполне конкретного популярного определения. Не приписывай мне лишнего.
Ты покритиковал спекуляции на тему оптимизаций в конце страницы о декларативности.
S>>Ты опять ушел куда-то на фронт. До потоков мы так и не дойдем, если не поймем что даже в одном потоке вызовы переставлять нельзя по причине побочных эффектов. ФП тут хорошо не тем, что оно позволяет явно выстроить последовательность без ";". А тем, что чистое ФП не оперирует побочными эффектами.
V>Тебе то что? Не ты же вызовы переставляешь, а компилятор. Выходи до боли знакомое кино, которое тыщу раз видел от функциональщиков: то они призывают компилятор в свидетели, что ему, оказывается, можно порядки вызовов менять как угодно, то когда говорю, что в императивном языке компилятор может делать тоже самое, т.к. способен довольно глубоко просмотреть все зависимости и увидеть степень их "локальности" — то ай, стоп, не надо обсуждать компилятор... Сорри, это несерьезно.
Это ты призываешь компилятор в свидетели императивности ФП. Меня не подписывай. Свойства компилятора ФП это следствие декларативности. Из того что компилятор или процессор может переставить инструкции еще не значит что исходный код декларативен. Если для тебя и SELECT императивен, то надо завязывать с этим трепом.
V>Меня на самом деле интересует лишь кол-во описываемых подробностей в программе, а не то, каким образом компилятор будет колдовать над этим кодом в процессе его оптимизации. Вот что тебе с того, что компилятор способен там что-то менять в твоей программе без твоего ведома? Как это тебе помогает или мешает? Делая тоже самое для С++ компилятор не делает мне ни холодно ни жарко до тех пор, пока заданная мною семантика сохраняется. (Доп. быстродействие, конечно бонус, но оно пока не доступно функциональным языкам, несмотря на все эти обещанные вещи)
Теперь количество подробностей. В определении декларативности ты видел что-то о количестве подробностей?
Мне по большому счету пофигу на перестановки. Но ведь ты к ним аппелируешь, а не я!!!
S>>Т.е. если ты возьмешь ИП и скомпозируешь его функции дабы избежать";", то все равно ты будешь зависеть от порядка вычисления аргументов. В чистом ФП — нет.
V>Не я буду зависеть, а компилятор. А мне-то что? А компиятор тоже не особо ко мне прислушается... Вот ты в упор не понимаешь, что тебе пишут. компилятор как раз тоже сможет вычислять в произвольном порядке до тех пор пока способен установить отсутствие неявных зависимостей м/у аргументами.
Я выделил ключевое. Сможет до тех пор. Я не пойму, какие выводы можно делать из возможности смены порядка, даже если декларативности может быть недостаточно для возможности изменения порядка (в рамках конкретной модели вычислений).
V>Кароч давай ты сделаешь паузу и подумаешь, что же есть побочный эффект, для начала. Вот есть пара вычисляемых выражений-аргументов ф-ии. Предположим, что эта пара не пишет ничего во "внешний мир" в процессе своих вычислений. Так вот, возвращаясь к началу поста относительно побочных эффектов: если эти выражения имеют пересекающиеся зависимости, которые модифицируются в процессе вычисления, то порядок вычисления аргументов важен, если же не имеют — не важен. Точка. Вот почему определение побочных эффектов Синклера всяко грамотнее рассуждений о "внешнем мире", бо последнее нечетко и неграмотно.
Я не очень формально понимаю что такое пересекающиеся зависимости. А вот внешний мир по отношению к выражению — это понятнее. Прежде чем ставить точку, убедись что твое выражение не только не пишет во внешний мир, но и не читает из него.
S>>Забудь ты про компиляторы. main у хаскеля описывает свой результат. main в C++ описывает последовательность действий с побочными эффектами (кроме тривиального случая int main() { return 0;}). Разница в этом.
V>Поправочка, main у Хаскеля описывает КАК ИМЕННО вычислить результат, что бы там кто ни говорил. И это описание в Хаскеле идет с ничуть не меньшими подробностями чем в каком-нить другом языке с уборкой мусора (не обязательно С++).
main у Хаскеля описывает ЧТО ИМЕННО является ее результатом. Как именно он будет вычислен — я бы не взялся утверждать. Число и уровень подробностей значения не имеет.
V>Если честно, я прекрасно понимаю т.з. оппонентов, твою например.
Если так, то ты отлично делаешь вид что совершенно не понимаешь.
V>Я просто надеялся выбить ответные аргументы, вместо слышимых по этому вопросу только лишь "не согласен, это другая т.з." и т.д. Бо противоречие в нынешних определениях налицо. А противоречие это возникло не на пустом месте, так всегда бывает, когда взятое изначально слово в кач-ве термина для обозначения похожих происходящих вещей потом пытается быть пересомтренным. И тогда вместо аксиоматичного понимания сути термина возникают поправки, толкования, объяснения и прочее чтобы показать, почему это некое знакомое слово используется в незнакомом качестве. По мне вся эта возня с насильственной мутацией терминов искуственна и притянута за уши, лучше было бы придумать другой термин, например для обсуждаемого подходит "прозрачность" или что-то в этом духе.
Извини, я совершенно не понимаю, о чем ты думаешь, когда утверждаешь что if в Хаскеле имеет побочные эффекты. Приходится сомневаться в адекватности понимания тобой терминов, которые ты употребляешь, явлений, которые ты описываешь. Когда ты утвреждаешь что споришь с определением, ты говоришь о компиляторах, перстановках, многопоточности, оптимизациях, императивности вычислителей и т.п. Обо всем, но не о способе выражения логики вычислений, относительно которого сформулировано определение. Ты споришь с собой, какими-то предрассудками, но не с определением.
Прежде чем выбивать ответные аргументы, позволь для начала вернуть тебя в плоскость обсуждаемого вопроса.