-
> Григорьев Антон © (06.05.08 13:27) [132] > > > oxffff © (06.05.08 12:33) [127] > > Во-первых, как копируются записи типа TVarRec, я знаю, о > чём уже писал. Не вижу смысла в вашем повторении. >
Тогда что вы хотели сказать своим утверждением, что использование CopyMemory недопустимо?
> > > Я вам 865 раз повторяю проблема здесь не CopyMemory, а > в > > том что вы не понимаете как работает TVarRec. :) > > Вот пример > > > > procedure abc(a:array of const;b:array of const); > > begin > > a[1]:=b[1]; <- Здесь простое копирование. > > > > > end; > > > > procedure TForm1.Button1Click(Sender: TObject); > > begin > > abc([1],[2]); > > end; > > Ну да, простое копирование. И что, какой глубокий смысл > у этого примера? Что я должен увидеть такого, что убедит > меня в моей неправоте? Вы бы договаривали свои аргументы > до конца, что ли, а то слишком они голословны.
Это я к тому что CopyMemory не вносит ошибок, а выполняет копирование в соответствии с согласшением копирования TvarRec.
> > А вот указать конкретную ошибку в моих рассуждениях вы не > смогли. Опять рассуждения о том, что я якобы не знаю, как > копируется TVarRec. Знаю, что там простое копирование, и > с самого начала из этого исходил. Что вы хотите доказать, > бесконечно повторяя то, с чем я и так согласен?
А хочу я вам показать, что пример использования финализируемого типа вами некорректно выполнен. Ответ см. далее.
> > > Вы как программист должны наконец изучить работу типа > TVarRec. > > > > Семантика копирования отличается о TVarData. > > Чем? Посмотрел, какой код генерируется в том и в другом > случае - везде простое копирование, только в одном случае > 8-и байт, поэтому идёт через eax по частям, в другом - 16- > ти байт, поэтому идёт через четырёхкратный вызов movsd. > Поясните, пожалуйста, подробнее про отличия в семантике. >
В том то и дело, что отличия от Copymemory нет. Почему конструктор статиического массива TVarRec у вас не вызывает подозрений? А от меня вы требуете чтобы я нарушал семантику типа, выполняя глубокое копирование.
> > > Вот вам ваши же грабли на вполне корретном с точки зрения > > > синтаксиса примере. > > Повторяю ещё раз свои слова: При таком подходе имеется гарантия > (за исключением редких случаев извращений с глобальными > переменными или параллельной передачей элементов массива > через другие параметры функции), что время жизни массива > меньше, чем время жизни его элементов, поэтому такое простое > копирование не приводит к осложениям.
Копирование происходит согласно семантики типа. А осложнение которое вы придумываете в своих постах, вызвано тем, что вы осознанно нарушаете соглашение TvarRec передавая финализируемый тип. А если вы это делаете осознанно, и как вы говорите знаете как это работает, чему я очень рад, то и ответственность за время жизни несете имеено вы(программист). А если вы не понимаете работу TVarRec - это другой вопрос
> > Вы опять меня пытаетесь убедить в том, что я уже писал и > о чём я прекрасно осведомлён и без вас. Зачем? Вы не вдумываетесь > в мои слова? > > > Когда вы наконец пойтете как работает TvarRec. Тогда вы > > > поймете как правильно передавать строки. > > А именно использовать для этого то что ждет от вас TVarRec. > > > > > var a:string[10]; > > Не вопрос. Переделываем Button1Click из кода в [97] так: > > procedure TForm1.Button1Click(Sender: TObject); > var > A:VarRecArray; > S:string[10]; > begin > S:='abc'; > A:=TrickInit([S]); > S:='123'; > abc(A,XSample); > ASSERT(A[0].VType = vtString); > Label1.Caption:=A[0].VString^ > end; > Выводится "123", хотя в список мы вроде как записывали "abc". > Проблема, думаю, вам понятна: в A[0] на самом деле сохраняется > не строка, а указатель на переменную S. Немножко пошаманив, > можно добиться того, чтобы на момент использования этого > указателя переменной S уже не существовало, а память была > занята чем-то другим, тогда будет совсем весело.
Вы опять не поняли. Использование строки в стеке, гарантирует ее жизнь на этапе всей работы функции и не приводит к AV. Пример приведен для того, что использование array of const налагает ограничения, а именно на управляемые типы. А именно коли вы передали данные этих типов, то будьте добры обеспечивайте существование их экземпяров на этапе работы. И беда эта не в том, что TrickInit как то не так написан, а в том, что такова семантика TvarRec.
Итог: string[10], > который вы рекомендовали, также не позволяет использовать > списки элементарных типов в стиле Лиспа. Тут же возникает > куча оговорок, которые не дают выполнить многих действий.
Тут возникает другой вывод, что использование TvarRec в качестве костылей, налагает ограничения не на костыли, а на семантику типа TvarRec.
> Но в любом случае, к разработчикам Delphi претензий нет. > Они дали инструмент с вполне понятной областью применимости > и ограничениями, и каждый волен использовать или не использовать > его. Претензии есть к конкретному человеку под ником oxffff, > который утверждает, что этот инструмент достаточно гибок, > чтобы заменить списки Лиспа, но при этом все решения, которые > он предлагает, оказываются намного более ограниченными, > чем Лисп. Не надо сводить вопрос "можно ли так, как в Лиспе" > к вопросу "как правильно использовать TVarRec. Если вы можете > написать такую функцию на основе TVarRec, с помощью которой > программист, как в Лиспе, сможет не думать ни о какой семантике > копирования, напишите.
Хм. В каждом языке есть свои правила. И лезть со своими более чем странно. Если вы не знаете принцип работы TVarRec, то это ваши проблемы. :)
Поэтому если вы используте данные костыли, то должны знать принцип их устройства.
Я еще раз повторяю, что проблемы с финализируемым типом лежит в не реализации костылей, а самой природе TVarRec. И мне очень жаль, что вы пытаетсь переложить на меня эту ответственность.
Если нет - не надо уходить в сторону > и рассуждать о том, как надо использовать TVarRec. А решения, > которое работало бы и с простыми типами, и со строками > без обёрток вы так и не показали.
Я вам показал еще два способа с обертками. В которых семантика копирования "правильная" по сравнению с семантикой TVarRec.
-
Игорь Шевченко © (06.05.08 12:57) [130] Но на этом форуме у посетителей наблюдается одна похожая болезнь, они не вникают в смысл дискуссии и начинают ловить блох в конкретных словах конкретных постов конкретных авторов
Игорь, вы кстати этим же страдаете. Частенько вы выдираете из страничного поста некую фразу и опровергаете ее, хотя ее правдивость на весь смысл поста может практически и влияния не оказывать, то есть это не ключевой момент.
-
> Григорьев Антон © (06.05.08 13:32) [133] > > > oxffff © (06.05.08 12:39) [128] > > To Григорьев Антон © > > > > Проблема в том что любое использование TvarRec обязывает > > > вас(программиста) управлять временем жизни ручным способом. > > > > > Такова семантика типа TvarRec, которую я не нарушаю. > > TVarRec - это внутренняя кухня хранения списков. Если вы > не можете предложить такой метод работы со списками, который > позволяет программисту не думать о внутренней кухне, а работать > на более высоком уровне абстракции, значит, вы не можете > предложить столь же общего решения, какое даёт Лисп. Что > и требовалось доказать.
Если вы находитесь на кухне в гостях, то соблюдайте правила этого дома. :)
-
Пробегал2... (06.05.08 16:10) [141]
Читаем правила форума долго и внимательно. Не удивляемся потом репрессиям.
-
oxffff © (06.05.08 16:09) [140]
> Хм. В каждом языке есть свои правила.
Об чем, собственно, речь на протяжении многих постов. В LISP свои правила, в Delphi свои. Попытка их смешать может привести к созданию совершенно неудобных в работе монстров.
Кстати, аналогичная фигня, но гораздо проще для понимания - это функции с переменным числом аргументов. В С они встроены в язык, реализация их на Delphi прямо скажем, затруднительна.
-
> oxffff © (06.05.08 16:11) [142] > Если вы находитесь на кухне в гостях, то соблюдайте правила > этого дома. > :)
Подвожу итог. Фактически, вы подтвердили, что программировать в стиле Лиспа на Delphi нельзя. Именно это я и сказал в своём сообщении, с которого начались ваши нападки. Спорить, видимо, больше не о чем. Согласны? > Я еще раз повторяю, что проблемы с финализируемым типом > лежит в не реализации костылей, а самой природе TVarRec. > > И мне очень жаль, что вы пытаетсь переложить на меня эту > ответственность.
Я пытаюсь возложить на вас ответственность за то, чтобы ваша функция правильно работала со строковыми типами. Добьётесь ли вы этого с помощью TVarRec или нет, это вопрос вторичный. Если TVarRec не умеет этого делать, то либо придумайте ему замену, либо признайте, что работать со списками простых типов в Delphi так же, как в Лиспе, не получится. Всё остальное будет пустой демагогией. > >А решения, > > которое работало бы и с простыми типами, и со строками > > > без обёрток вы так и не показали. > > > Я вам показал еще два способа с обертками. > В которых семантика копирования "правильная" по сравнению > с семантикой TVarRec.
Я же русским языком написал, что "как в Лиспе" - это значит без обёрток, а потому любые варианты с обёртками я в принципе не считаю решениями. Зачем вы снова и снова говорите про них? > А хочу я вам показать, что пример использования финализируемого > типа вами некорректно выполнен.
Некорректно выполнена ваша функция, которой семантика языка не мешает получать на вход финализируемые данные, но которая, тем не менее, написана так, как будто такого не может быть никогда. Я так понял, вы исповедуете принцип "раз разработчики Delphi об этом не позаботились, то и я не буду". Только так далеко не уедешь, если вы хотите получить в итоге не просто работающий код, а более высокоуровневую абстракцию. Вы её и не смогли сделать. > Вы опять не поняли. > Использование строки в стеке, гарантирует ее жизнь на этапе > всей работы > функции и не приводит к AV.
Да, но кто гарантирует, что она обязана быть в стеке на том же уровне, что и результат TrickInit? Вот пример: procedure TForm1.Button1Click(Sender: TObject);
var
A:VarRecArray;
procedure InitA;
var
S:string[10];
begin
S := 'abc';
A := TrickInit([S])
end;
begin
InitA;
abc(A,XSample);
ASSERT(A[0].VType = vtString);
Label1.Caption:=A[0].VString^
end; К моменту, когда мы обращаемся к A [0], переменной S уже не существует, хотя A [0] продолжает хранить указатель на неё. Так что string [10] - это никакой не итог, просто тут появляются другие заморочки. Которых, повторяю, нет в Лиспе. А значит, ваше решение не катит на "в Delphi можно писать в стиле Лиспа".
-
> Григорьев Антон © (06.05.08 16:35) [145]
На остальное отвечу вечером.
> Да, но кто гарантирует, что она обязана быть в стеке на > том же уровне, что и результат TrickInit? Вот пример: > procedure TForm1.Button1Click(Sender: TObject); > var > A:VarRecArray; > > procedure InitA; > var > S:string[10]; > begin > S := 'abc'; > A := TrickInit([S]) > end; > > begin > InitA; > abc(A,XSample); > ASSERT(A[0].VType = vtString); > Label1.Caption:=A[0].VString^ > end; > К моменту, когда мы обращаемся к A[0], переменной S уже > не существует, хотя A[0] продолжает хранить указатель на > неё. Так что string[10] - это никакой не итог, просто тут > появляются другие заморочки. Которых, повторяю, нет в Лиспе. > А значит, ваше решение не катит на "в Delphi можно писать > в стиле Лиспа".
Все катит. Нужно только использовать правильно. Только опять этот пример из разряда особенности работы типа умело сфабрикованный вами. Вы внимательно прочитали, то что я выделил жирным?
А осложнение которое вы придумываете в своих постах, вызвано тем, что вы осознанно нарушаете соглашение TvarRec передавая финализируемый тип. А если вы это делаете осознанно, и как вы говорите знаете как это работает, чему я очень рад, то и ответственность за время жизни несете имеено вы(программист).
Однако я предложил не один вариант. Может рассмотрим и их тоже. Поскольку семантика там правильная, то и проблем меньше.
Предлагаю продолжить вечером. :) Сейчас опять R3 и таблица LIPS ждет меня.
-
> oxffff © (06.05.08 16:47) [146]
Это вы невнимательно читаете то, что я написал. Речь не идёт о том, как правильно работать с TVarRec и array of const. Речь идёт о том, чтобы работать, как в Лиспе. А это значит, что не нужно думать ни об особенностях типа, ни о времени жизни параметров, ни о том, как выделяется память для них, потому что обо всём этом компьютер позаботится автоматически, и позаботится правильно. Своими "сфабрикованными" примерами я хочу показать только одно: вы этого не достигли. Программист должен думать о времени жизни, о том, как выделяется и освобождается память, о том, данные какого типа он передаёт. Вы всё это уже признали, и я не понимаю, почему вы не согласны с тем, что сделать в Delphi, как в Лиспе, с помощью TVarRec у вас не получилось.
> Однако я предложил не один вариант. > Может рассмотрим и их тоже. Поскольку семантика там правильная, > то и проблем меньше.
Ещё раз повторяю, что значит "как в Лиспе":
1. Программист не думает о времени жизни и размещении в памяти данных, это всё отслеживается автоматически. 2. Программист работает со всякими типами данных, в т.ч. и с элементарными, без всяких обёрток. 3. Можно использовать любые функции, даже те, которые содержатся в библиотеках, авторы которых ничего не знали о ваших вариантах имитации Лиспа (встроенные функции я готов вам простить - это compiler magic, с ними мы не будем связываться).
Если хотя бы одно из этих условий не выполнено, то рассматривать соответствующий вариант - бесполезная трата времени, потому что "как в Лиспе" всё равно уже не будет.
Заметьте, я не внёс в этот список анонимные функции, функции высших порядков и замыкания (closures), без которых, строго говоря, Лисп немыслим. Просто это было бы совсем жестоко :)))))))) Выполните хотя бы сильно урезанный список из трёх пунктов, который выше.
И ещё один вопрос: а вы хорошо знаете Лисп? Или хотя бы какой-нибудь другой функциональный язык программирования? А то меня терзают смутные сомнения насчёт того, что вы просто не понимаете, что такое "как в Лиспе" и поэтому даже не представляете себе объём задачи, которую сами себе поставили.
-
> Кстати, аналогичная фигня, но гораздо проще для понимания > - это функции с переменным числом аргументов. В С они встроены > в язык, реализация их на Delphi прямо скажем, затруднительна. >
таки проблема не в языке. дельфя позволяет вызывать подобные сишные функции.
Просто в дельфи нету необходимости в такой фишке, так как есть array of Variant и array of const
-
> Просто в дельфи нету необходимости в такой фишке, так как > есть array of Variant и array of const
ровно наоборот - в делфи придумали array of Variant и array of const, потому что нету функций с переменным числом аргументов
-
> Просто в дельфи нету необходимости в такой фишке, так как > есть array of Variant и array of const
а проблема писать в случае отсутствия аргументов [] ?
Кстате, вот writeln - она истинно с переменным числом. Значит, необходимость в фишке таки есть ?
-
> И ещё один вопрос: а вы хорошо знаете Лисп? Или хотя бы > какой-нибудь другой функциональный язык программирования? > А то меня терзают смутные сомнения насчёт того, что вы > просто не понимаете, что такое "как в Лиспе" и поэтому даже > не представляете себе объём задачи, которую сами себе поставили. >
Нет с лиспом я не знаком. Однако, что такое closures и анонимные функции знаю. Closures - это объект управляемой кучи. анонимные функция - функция объявленная по месту, а фактически указатель на нее. НО честно говоря не вижу особых препятствий для реализации. Однако поскольку нет GC, то управлять временем жизни closure придется вручную. Я честно говоря по данному вопросу веду диалог в newsgroup по реализации анонимных методов в Delphi for win32 анонсированных недавно.
-
> Григорьев Антон © (06.05.08 17:13) [147] > > > oxffff © (06.05.08 16:47) [146] > > Это вы невнимательно читаете то, что я написал. Речь не > идёт о том, как правильно работать с TVarRec и array of > const. Речь идёт о том, чтобы работать, как в Лиспе. А это > значит, что не нужно думать ни об особенностях типа, ни > о времени жизни параметров, ни о том, как выделяется память > для них, потому что обо всём этом компьютер позаботится > автоматически, и позаботится правильно. Своими "сфабрикованными" > примерами я хочу показать только одно: вы этого не достигли. > Программист должен думать о времени жизни, о том, как выделяется > и освобождается память, о том, данные какого типа он передаёт. > Вы всё это уже признали, и я не понимаю, почему вы не согласны > с тем, что сделать в Delphi, как в Лиспе, с помощью TVarRec > у вас не получилось. >
Напонимаю, что ваши претензии начались с вопроса о некорректности CopyMemory и лично я все же остаюсь при мнении, что семантику копирования TvarRec вы узнали от меня из этой ветки. :) Я остаюсь при мнении, что достичь результата можно с TVarRec можно, но при соблюдении некоторых правил навязынных концепцией разработчиков Delphi на тип семантику типа TVarRec. Да синтаксис не такой, а что вы хотели.
Вечером продолжим с variant.
-
> Нет с лиспом я не знаком.
Познакомься :) Для расширения кругозора всяко полезно будет.
-
Удалено модератором
-
> Григорьев Антон © (06.05.08 17:13) [147]
Меняем TvarRec на TVarData.
type TUnaryFunc=function (var Value:variant):variant; TArrayOfVariant=array of variant;
function SomeUnaryFunc(var Value:variant):variant; begin showmessage(value); end;
function ForEachDo(var List:array of variant;UnaryFunc:TUnaryFunc):integer; var i:integer; begin for i:=0 to length(List)-1 do List[i]:=UnaryFunc(List[i]); end;
function TrickInit(List:array of variant):TArrayOfVariant; var p:pointer; Count:integer; Res:pointer; begin Count:=length(List); setlength(result,Count); Copymemory(Result,@list,Count*SizeOf(variant)); p:=typeinfo(Variant); Res:=result; asm mov ecx,Count; mov edx,p; mov eax,Res; call system.@AddRefArray; end; end;
procedure TForm1.Button1Click(Sender: TObject); var i:integer; ArrayOfVariant:TArrayOfVariant; begin ArrayOfVariant:=TrickInit(['HI ALL','HERE WE ARE',1,2,3]); ForEachDo(ArrayOfVariant,SomeUnaryFunc); end;
-
> Заметьте, я не внёс в этот список анонимные функции, функции > высших порядков и замыкания (closures), без которых, строго > говоря, Лисп немыслим. Просто это было бы совсем жестоко > :)))))))) Выполните хотя бы сильно урезанный список из трёх > пунктов, который выше.
Можете прочитать мой блог. Реализация С# yield на Delphi. http://santonov.blogspot.com/2007/10/yield-you.htmlТам как раз используется аналог closure в виде сохранения Machine State, во всяком смысл тот же - захват внешних переменных.
-
> oxffff © (06.05.08 18:07) [152] > Напонимаю, что ваши претензии начались с вопроса о некорректности > CopyMemory
Ошибаетесь. Наш разговор начался гораздо раньше, с моего сообщения [50] и последовавших за этим ваших не слишком вежливых ответах. > и лично я все же остаюсь при мнении, что семантику копирования > TvarRec вы узнали от меня из этой ветки. :)
Да, я уже почти привык к тому, что у вас в отношении меня регулярно возникают фантазии, которые непонятно откуда берутся. И вы, кажется, так и не поняли, в чём суть наших с вами разногласий по поводу использования CopyMemory. Вы рассуждаете примерно так: "Раз авторы Delphi не предусмотрели работу с финализируемыми типами, то и я не буду об этом заботится, а тот, кто передал в мою функцию строку и получил битый указатель - сам дурак, потому что не понимает семантику TVarRec". Я такой подход не приемлю в принципе. Я считаю, что тот, кто пишщет функцию, которую будут использовать другие люди, обязан предусмотреть для неё корректное поведение при любых входных данных. Если компилятор допускает передачу строки в качестве параметра, рано или поздно кто-то её передаст. И ваша функция, если вы считаете такой параметр недопустимым, должна выкинуть исключение, а не втихую запороть указатель, заложив в программу мину замедленного действия, которая сработает неизвестно где. Другими словами, функция должна обеспечивать определённый уровень абстракции, а не заставлять пользователя вникать во внутреннюю кухню. По моему глубокому убеждению, если функция этого не обеспечивает, это говорит о низком профессионализме того, кто её писал, и никакие ссылки на семантику типа здесь не катят. > Я остаюсь при мнении, что достичь результата можно с TVarRec > можно, но > при соблюдении некоторых правил навязынных концепцией разработчиков > Delphi на тип семантику типа TVarRec. > Да синтаксис не такой, а что вы хотели.
Да речь, вообще-то, идёт не о таком же синтаксисе, а о таких же возможностях. Вы пока этого не продемонстрировали, так как возможности вашей функции сильно урезаны по сравнению с Лиспом. Так что ваше мнение остаётся не более чем вашим мнением. > oxffff © (06.05.08 20:34) [155] > Меняем TvarRec на TVarData.
Всё-таки не на TVarData, а на Variant. Я, конечно, знаю, что Variant основан на TVarData, но ведь если объявить var A, B:TVarData, то A:=B также будет простым копированием, как и в случае TVarRec. Чтобы включились механизмы управления временем жизни, нужен всё-таки Variant. Начнём сначала с мелочей. в Лиспе никогда не модифицируется имеющийся список, любые операции над списком приводят к созданию нового списка. Поэтому ваша функция ForEachDo должна выглядеть так: function ForEachDo(List: array of variant; UnaryFunc: TUnaryFunc): TArrayOfVariant;
var
I: Integer;
begin
SetLength(Result,Length(List));
for I := 0 to High(List) do
Result[I] := UnaryFunc(List[I]);
end; Тогда и функция TrickInit становится не нужна, можно писать просто ForEachDo(['HI ALL','HERE WE ARE',1,2,3],SomeUnaryFunc); Но это решение только для простых типов. Чтобы было как в Лиспе, нужно, чтобы ForEachDo умела работать с любым списком, а в Лиспе элементами списка могут быть другие списки. Вот, скажем, такой пример. Пусть у нас есть функция SumList, которая на входе принимает список, на выходе выдаёт число - сумму его элементов. Тогда должна быть допустима такая конструкция (пишу в синтаксисе Паскаля, чтобы было понятнее) ForEachDo([[1,2,3], [4,5,6], [7,8,9]], SumList); На выходе должен получится список [6, 15, 24]. Глупый вопрос: сможет ли ваша функция реализовать такое? Без обёрток - вряд ли. Кстати, вариант вида ForEachDo([VarArrayOf([1,2,3]),VarArrayOf([4,5,6]),VarArrayOf([7,8,9])],Su mList); на "как в Лиспе" не тянет. Уже догадались, почему, или требуются пояснения?
-
Прочитал про ЛИСП и подумал про себя : круче клиппера языка нету :) Мона писать свои операторы (расширять язык - я так сделал для оконного вывода и печати), мона исполнять любые выражения из строки. Причем не только числовые. Есть массивы переменной размерности. Все остальное мона прикрутить. Потом еще подумал : а в делфи при желании мона прикрутить практически тоже самое.
-
Да, а на скл сортировка пишется в одну строку :)
|