-
> oxffff © (06.05.08 10:45) [109] > Мой пример будет работать, если вы знаете как устроен Delphi.
Правда будет? "Будет работать" в контексте нашей беседы означает "будет работать как в Лиспе". В Лиспе можно работать со строками. Ваш пример, в котором вы используете CopyMemory, со строками работать не может. Следовательно, как в Лиспе он работать не будет.
Специально разжёвываю подробно, чтобы в том случае, если вы со мной не согласны, вы могли указать, в каком именно пункте.
> Почему вы пытаетесь обвинить меня в том, как устроен TvarRec.
Извините, но это ваши фантазии. Я вас в этом не обвинял.
> И более того пытались мне вменить ошибку с CopyMemory (см > ) > > Напоминаю вам ваш пост > > Григорьев Антон © (05.05.08 22:12) [90] > Будете использовать CopyMemory с автоматически финализируемым > типом? > > TvarRec - имеет простую семантику копирования. > > Поэтому ситуацию которые вы смоделировали относится к TvarRec, > а не к моей реализации.
Снова разжёвываю по буквам. Чтобы вам было понятно, в чём именно я вас обвиняю. Нумерую свои утверждения, чтобы вам легче было указать, какое из них конкретно кажется вам неправильным.
1. Конструктор открытого вариантного массива позволяет передавать строки в качестве элементов массива. Строки при этом трактуются как AnsiString.
2. При передаче элементов открытого вариантного массива через стек элементы финализируемых типов просто копируются как указатели, механизм подсчёта ссылок при этом не задействется.
3. При таком подходе имеется гарантия (за исключением редких случаев извращений с глобальными переменными или параллельной передачей элементов массива через другие параметры функции), что время жизни массива меньше, чем время жизни его элементов, поэтому такое простое копирование не приводит к осложениям. (Поясню: сам массив перестаёт существовать в эпилоге "его" функции, а финализация элементов массива может происходить не раньше чем сразу после возврата из этой функции.)
4. Время жизни результата, который возвращает ваша функция TrickInit, в общем случае непредсказуемо и может быть существенно больше, чем время жизни элементов массива.
5. Простое копирование ссылок на финализируемые данные с помощью CopyMemory или иным подобным способом в тех случаях, когда нет гарантии, что копия не переживёт оригинал - абсолютно безграмотное действие. Именно это я и хотел сказать с самого начала.
6. Компилятор никак не защищает вашу функцию от передачи в неё строк. Следовательно, если вы применяете методы, которые для строк не подходят, вы должны сами предусмотреть защиту, благодаря которой функция будет работать правильно или сообщать об ошибке (например, выкидывая исключение). Вы этого не сделали.
Вот, собственно, какие именно у меня претензии к вашему коду.
> Вы сначала пытались прицепится к CopyMemory. А потом когда > я вам популярно объяснил, что TvarRec не автоматически финализируемый > пытались мне вменить свое незнание. :)
Я не утверждал, что TVarRec финализируемый. Я утверждал (и продолжаю утверждать), что в вашем случае ссылка на финализируемые данные может попасть в TVarRec и не будет учтена при подсчёте ссылок, а вы ничего не сделали, чтобы предотвратить это. Всё остальное - ваши личные фантазии, за которые я не могу нести ответственности.
> Я вам написал три варианта решения. > > Кстати как там ваше домашнее задание? см. выше
Во-первых, предупреждаю, что я последний раз терплю ваше хамство. Чтобы разговаривать таким тоном и раздавать домашние задания, надо иметь подавляющее превосходство в знаниях и опыте. Вы уверены, что оно у вас есть?
Далее, я вам с самого начала сказал, что "как в Лиспе" - это работа с простыми типами без всяких обёрток, поэтому ООП и TCustomVariant здесь не при чём - они не отвечают начальному условию задачи. Если вы этого до сих пор не поняли, то я тоже не могу нести за это ответственности. Что касается третьего варианта (точнее, первого в хронлогическом порядке), то он не умеет работать со строками. Так что вы пока не предложили ни одного решения, которое было бы сравнимо по общности с Лиспом. А вовсе не три, как вы здесь пишете.
-
crux (06.05.08 11:26) [118]
Можно написать так:
#include <string> use namespace std;
string foo;
foo = string("foo") + "bar";
Cложение констант на С можно написать и так foo = "foo""bar", если нужно зачем-то сложить именно константы.
Если одна из переменных в выражении имеет тип string, то оператор + практически всегда будет работать.
-
> Вариант на TVarRec самый простой и менее гибкий.
Верю. Есть и более гибкие :) На взять произвольную функцию sin(double) и засунуть её в этот mapcar без обёртки не получится :)
Можно вообще заменить все функции на классы, реализующие метод Apply([]), а все значения на объекты и получить на базе дельфи язык с первоклассными функциями и проч. и проч.
И не надо никакого хакинга, битов, байтов и т.п. ООП в чистом виде. Вот только писать в таком стиле замучаешься :)
-
> foo = string("foo") + "bar";
Дык, об этом и речь. Конструктор вызывать приходится явно. Это "протечка абстракции" в терминологии Джоэля Спольски. Со стрингами, конечно же, это фигня, не проблема. А с mapcar`ом уже нет.
-
crux (06.05.08 11:38) [121]
> foo = string("foo") + "bar";
> Cложение констант на С можно написать и так foo = "foo""bar"
Видите ли, в Паскале можно написать var s: string; begin s := 'foo' + 'bar'; ...
Об чем, собственно, был спич с самого начала. О разнице работы со строками в С и в Паскале. Хотя и то и то переводится в машинные команды.
> оператор + практически всегда будет работать.
ключевое слово, надо понимать, "практически". Так в паскале оператор сложения работает всегда, а не практически всегда.
В теме идет речь о том, можно ли смоделировать конструкции одних языков в других языках и насколько модель будет точной. Часть авторов утверждает, что можно, часть утверждает, что целиком и полностью нельзя. Вот и все, пример с С был приведен для иллюстрации второй точки зрения.
-
Игорь Шевченко © (06.05.08 11:44) [124]
А как вы считаете, насколько точна модель работы со строками в c++ относительно ее же в паскале?
Можно считать, что они эквивалентны, так как авторы не учли наличие функционально схожих, но по-разному записываемых операций.
Например, вот такое выражение вполне себе будет работать
string r, s = "a";
r = s + "b" + "c" + "d";
и если рассматривать хвость "c" + "d", то фразу о том, что "Как ты ни бейся, а сделать так, что бы выражение "bla-bla-bla" + "bu-bu-bu" на С++ занималось конкатенацией строк, а не сложением указателей, не выйдет." не верно.
такое уже не будет работать
r = "b" + "c" + s + "d";
но первый оператор можно заменить на функционально-идентичный эквивалент
r = "b""c" + s + "d";
и все прекрасно заработает.
-
> crux (06.05.08 11:59) [125]
Кто же спорит? Однако это уже иллюстрация к тому, то *точно* воспроизвести некоторые абстракции одного языка на другом не всегда получается. И это, кстати, крайне примитивный случай - строки в двух очень похожишь по идеологии языка.
-
> Григорьев Антон © (06.05.08 11:37) [120] > > > oxffff © (06.05.08 10:45) [109] > > Мой пример будет работать, если вы знаете как устроен > Delphi. > > Правда будет? "Будет работать" в контексте нашей беседы > означает "будет работать как в Лиспе". В Лиспе можно работать > со строками. Ваш пример, в котором вы используете 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;
> > Специально разжёвываю подробно, чтобы в том случае, если > вы со мной не согласны, вы могли указать, в каком именно > пункте. > > > Почему вы пытаетесь обвинить меня в том, как устроен TvarRec. > > > Извините, но это ваши фантазии. Я вас в этом не обвинял. > > > > И более того пытались мне вменить ошибку с CopyMemory > (см > > ) > > > > Напоминаю вам ваш пост > > > > Григорьев Антон © (05.05.08 22:12) [90] > > Будете использовать CopyMemory с автоматически финализируемым > > > типом? > > > > TvarRec - имеет простую семантику копирования. > > > > Поэтому ситуацию которые вы смоделировали относится к > TvarRec, > > а не к моей реализации. > > Снова разжёвываю по буквам. Чтобы вам было понятно, в чём > именно я вас обвиняю. Нумерую свои утверждения, чтобы вам > легче было указать, какое из них конкретно кажется вам неправильным. > > > 1. Конструктор открытого вариантного массива позволяет передавать > строки в качестве элементов массива. Строки при этом трактуются > как AnsiString. > > 2. При передаче элементов открытого вариантного массива > через стек элементы финализируемых типов просто копируются > как указатели, механизм подсчёта ссылок при этом не задействется. > > > 3. При таком подходе имеется гарантия (за исключением редких > случаев извращений с глобальными переменными или параллельной > передачей элементов массива через другие параметры функции), > что время жизни массива меньше, чем время жизни его элементов, > поэтому такое простое копирование не приводит к осложениям. > (Поясню: сам массив перестаёт существовать в эпилоге "его" > функции, а финализация элементов массива может происходить > не раньше чем сразу после возврата из этой функции.) >
> 4. Время жизни результата, который возвращает ваша функция > TrickInit, в общем случае непредсказуемо и может быть существенно > больше, чем время жизни элементов массива.
Вы предлагаете мне нарушить семантику типа TvarRec? Я вам привел уже несколько примеров.
> > 5. Простое копирование ссылок на финализируемые данные с > помощью 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;
> 6. Компилятор никак не защищает вашу функцию от передачи > в неё строк. Следовательно, если вы применяете методы, которые > для строк не подходят, вы должны сами предусмотреть защиту, > благодаря которой функция будет работать правильно или > сообщать об ошибке (например, выкидывая исключение). Вы > этого не сделали.
> > Вот, собственно, какие именно у меня претензии к вашему > коду. > > > Вы сначала пытались прицепится к CopyMemory. А потом когда > > > я вам популярно объяснил, что TvarRec не автоматически > финализируемый > > пытались мне вменить свое незнание. :) > > Я не утверждал, что TVarRec финализируемый. Я утверждал > (и продолжаю утверждать), что в вашем случае ссылка на финализируемые > данные может попасть в TVarRec и не будет учтена при подсчёте > ссылок, а вы ничего не сделали, чтобы предотвратить это. > Всё остальное - ваши личные фантазии, за которые я не могу > нести ответственности. >
Вы как программист должны наконец изучить работу типа TVarRec. Семантика копирования отличается о TVarData.
> > Я вам написал три варианта решения. > > > > Кстати как там ваше домашнее задание? см. выше > > Во-первых, предупреждаю, что я последний раз терплю ваше > хамство. Чтобы разговаривать таким тоном и раздавать домашние > задания, надо иметь подавляющее превосходство в знаниях > и опыте. Вы уверены, что оно у вас есть? > > Далее, я вам с самого начала сказал, что "как в Лиспе" - > это работа с простыми типами без всяких обёрток, поэтому > ООП и TCustomVariant здесь не при чём - они не отвечают > начальному условию задачи. Если вы этого до сих пор не поняли, > то я тоже не могу нести за это ответственности. Что касается > третьего варианта (точнее, первого в хронлогическом порядке), > то он не умеет работать со строками. Так что вы пока не > предложили ни одного решения, которое было бы сравнимо по > общности с Лиспом. А вовсе не три, как вы здесь пишете.
Первый вариант не нарушает семантику типа TvarRec. Повторяю не нарушает.
В этом примере при создании локальной копии также происходит копирование простое без анализа типа.
Вот вам ваши же грабли на вполне корретном с точки зрения синтаксиса примере.
var GlobalA:string;
procedure abc(a:array of const;b:array of const); begin GlobalA:=''; a[1]:=a[0]; a[0]:=b[0]; Showmessage(pchar(a[1].VString)) <- это делать небезопасною. end;
procedure TForm1.Button1Click(Sender: TObject); var a:string; begin GlobalA:=a+'bbb'; abc([GlobalA,1],[555]); end;
Когда вы наконец пойтете как работает TvarRec. Тогда вы поймете как правильно передавать строки. А именно использовать для этого то что ждет от вас TVarRec. var a:string[10];
И это все от вашего незнания.
-
To Григорьев Антон ©
Проблема в том что любое использование TvarRec обязывает вас(программиста) управлять временем жизни ручным способом. Такова семантика типа TvarRec, которую я не нарушаю.
-
> 5. Простое копирование ссылок на финализируемые данные с > помощью CopyMemory или иным подобным способом в тех случаях, > когда нет гарантии, что копия не переживёт оригинал - абсолютно > безграмотное действие. Именно это я и хотел сказать с самого > начала. > > 6. Компилятор никак не защищает вашу функцию от передачи > в неё строк. Следовательно, если вы применяете методы, которые > для строк не подходят, вы должны сами предусмотреть защиту, > благодаря которой функция будет работать правильно или > сообщать об ошибке (например, выкидывая исключение). Вы > этого не сделали.
Я работаю с TVarRec и знаю семантику копирования этого типа, которая выполняет поэлементное копирование. Поэтому при работе с этим типом ответственность за LifeTime лежит на программисте. Поэтому эти претензии не ко мне, а к Хейлсбергу.
-
crux (06.05.08 11:59) [125]
Опять за рыбу деньги.
Можно заменить и на foo = string("foo") + string("bar") - и будет прекрасно работать.
Речь совершенно о другом - речь о том, что не всегда возможно заменить конструкции одного языка реализацией на другом языке, строки в C(++) приведены как пример. Но на этом форуме у посетителей наблюдается одна похожая болезнь, они не вникают в смысл дискуссии и начинают ловить блох в конкретных словах конкретных постов конкретных авторов.
-
> Игорь Шевченко © (06.05.08 12:57) [130]
Это одна сторона медали. Другая сторона заключается в том, что вот работаешь, работаешь с каким-нибудь string в С++ (QString в Qt - вот кстати любят разные разботчики своих фремворков наворотить своих "особенных" причмочек для работы со строками), а потом надо тебе воспользоваться некой функцией, а она, собака, только char* понимает. И начинаются выкрутасы... Ну никак не получается паскалеподобная работа со строками.
-
> oxffff © (06.05.08 12:33) [127]
Во-первых, как копируются записи типа TVarRec, я знаю, о чём уже писал. Не вижу смысла в вашем повторении. > Я вам 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;
Ну да, простое копирование. И что, какой глубокий смысл у этого примера? Что я должен увидеть такого, что убедит меня в моей неправоте? Вы бы договаривали свои аргументы до конца, что ли, а то слишком они голословны. А вот указать конкретную ошибку в моих рассуждениях вы не смогли. Опять рассуждения о том, что я якобы не знаю, как копируется TVarRec. Знаю, что там простое копирование, и с самого начала из этого исходил. Что вы хотите доказать, бесконечно повторяя то, с чем я и так согласен? > Вы как программист должны наконец изучить работу типа TVarRec. > > Семантика копирования отличается о TVarData.
Чем? Посмотрел, какой код генерируется в том и в другом случае - везде простое копирование, только в одном случае 8-и байт, поэтому идёт через eax по частям, в другом - 16-ти байт, поэтому идёт через четырёхкратный вызов movsd. Поясните, пожалуйста, подробнее про отличия в семантике. > Вот вам ваши же грабли на вполне корретном с точки зрения > синтаксиса примере.
Повторяю ещё раз свои слова: При таком подходе имеется гарантия (за исключением редких случаев извращений с глобальными переменными или параллельной передачей элементов массива через другие параметры функции), что время жизни массива меньше, чем время жизни его элементов, поэтому такое простое копирование не приводит к осложениям.Вы опять меня пытаетесь убедить в том, что я уже писал и о чём я прекрасно осведомлён и без вас. Зачем? Вы не вдумываетесь в мои слова? > Когда вы наконец пойтете как работает 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 уже не существовало, а память была занята чем-то другим, тогда будет совсем весело. Итог: string [10], который вы рекомендовали, также не позволяет использовать списки элементарных типов в стиле Лиспа. Тут же возникает куча оговорок, которые не дают выполнить многих действий. > Я работаю с TVarRec и знаю семантику копирования этого типа, > которая выполняет поэлементное копирование. Поэтому при > работе с этим типом ответственность за LifeTime лежит на > программисте.
Да, это очень похоже на работу в Лиспе, где программист вообще не управляет распределением памяти, а время жизни определяется сборщиком мусора :))))))))))) > Поэтому эти претензии не ко мне, а к Хейлсбергу.
Есть у меня какие-то смутные воспоминания, что TVarRec и array of const появились в относительно поздних версиях Delphi, когда Хейлсберг уже Delphi не занимался... Но в любом случае, к разработчикам Delphi претензий нет. Они дали инструмент с вполне понятной областью применимости и ограничениями, и каждый волен использовать или не использовать его. Претензии есть к конкретному человеку под ником oxffff, который утверждает, что этот инструмент достаточно гибок, чтобы заменить списки Лиспа, но при этом все решения, которые он предлагает, оказываются намного более ограниченными, чем Лисп. Не надо сводить вопрос "можно ли так, как в Лиспе" к вопросу "как правильно использовать TVarRec. Если вы можете написать такую функцию на основе TVarRec, с помощью которой программист, как в Лиспе, сможет не думать ни о какой семантике копирования, напишите. Если нет - не надо уходить в сторону и рассуждать о том, как надо использовать TVarRec. А решения, которое работало бы и с простыми типами, и со строками без обёрток вы так и не показали.
-
> oxffff © (06.05.08 12:39) [128] > To Григорьев Антон © > > Проблема в том что любое использование TvarRec обязывает > вас(программиста) управлять временем жизни ручным способом. > > Такова семантика типа TvarRec, которую я не нарушаю.
TVarRec - это внутренняя кухня хранения списков. Если вы не можете предложить такой метод работы со списками, который позволяет программисту не думать о внутренней кухне, а работать на более высоком уровне абстракции, значит, вы не можете предложить столь же общего решения, какое даёт Лисп. Что и требовалось доказать.
-
Игорь Шевченко © (05.05.08 21:06) [86] Эт ты сказки рассказывай где-нибудь еще. Ты тут личность давно известная, повадки твои тоже
я видимо должен сгореть от стыда... Аргументы на грани фантастики.
Если вы судите о том, спорил ли я или нет лишь по моему нику - да на здоровье. Я предлагаю делать анализ на основании сказанного, а если вы перечитаете сказанное - я нигде не спорил. А уж как вам там хочется думать - ваше право.
-
oxffff, ну ты действительно не прав. Ты вместо выдачи универсального решения выдал ограниченное решение и объяснил ПОЧЕМУ оно ограниченное. Но кому нужно это объяснение? Решение не является общим и универсальным - и неважны причины, все, оно уже не такое как в LISP.
Или надо доказать, что в LISP тоже есть ограничения в решении.
-
Игорь Шевченко © (06.05.08 12:57) [130]
>Но на этом форуме у посетителей наблюдается одна похожая болезнь, они не вникают в смысл дискуссии и начинают ловить блох в конкретных словах конкретных постов конкретных авторов.
Если в высказываниях некоторых авторов наблюдаются вполне определенные искажения истинного положения вещей (например, такие, как утверждение об отсутствии типа string в C++), то некоторые другие авторы, которым эти искажения небезразличны, стремятся немного прояснить ситуацию. Это стоит так расценивать. Прощу прощения, конечно, за препирательства, но некоторые авторы тоже должны иметь совесть.
31512 (06.05.08 13:08) [131]
> Это одна сторона медали. Другая сторона заключается в том, > что вот работаешь, работаешь с каким-нибудь string в С++ > (QString в Qt - вот кстати любят разные разботчики своих > фремворков наворотить своих "особенных" причмочек для работы > со строками), а потом надо тебе воспользоваться некой функцией, > а она, собака, только char* понимает. И начинаются выкрутасы. > .. Ну никак не получается паскалеподобная работа со строками.
Опытные авторы, как правило, знают о экстракторах, о том как использовать vector<char> c legacy api для передачи и получения данных, извлекая указатель на первый элемент вектора и легким движением руки копируя его содержимое в string посредством алгоритма, либо использовании метода data() в некоторых реализациях, и как-то не жалуются особо, живя с этим. Что конечно для авторов практикующих паскаль может показаться непривычным. Окститесь. Мы ведь можем и о недостатках паскаля еще поговорить, но мы же не будем делать этого. Правда?
-
> Если в высказываниях некоторых авторов наблюдаются вполне > определенные искажения истинного положения вещей (например, > такие, как утверждение об отсутствии типа string в C++), > то некоторые другие авторы, которым эти искажения небезразличны, > стремятся немного прояснить ситуацию. Это стоит так расценивать. > Прощу прощения, конечно, за препирательства, но некоторые > авторы тоже должны иметь совесть.
Тут не было таких утверждений. Было утверждение, что работа со строками в С++ и в Паскале реализована немного по-разному и из-за особенностей языка С++ реализовать её ТОЧНО ТАК ЖЕ, как в паскале нельзя. Так что к совести предлагаю ещё прикладывать внимательность прочтения :) Большего не утверждалось.
-
crux (06.05.08 14:45) [136]
> Если в высказываниях некоторых авторов наблюдаются вполне > определенные искажения истинного положения вещей (например, > такие, как утверждение об отсутствии типа string в C++), >
Такой, как в Паскале - факт, отсутствует :) Я все-таки рекомендую читать весь пост, а не отдельные буквы. Аналогично прошу пардону за препирательство
-
> crux (06.05.08 14:45) [136]
Я не отношу себя к опытным авторам, по причине не знания определения такового.
> либо использовании метода data() в некоторых реализациях, > и как-то не жалуются особо
Я тоже думал, что мне будет не на что жаловаться... И возрадовался обнаружив QChar * QString::data (). Однако ж подлая void qDebug ( const char * msg, ... ) отказала мне два раза, нехочу, сказала, блин. Спасло QByteArray QString::toAscii () const. Вот и надейся потом на всякие реализации метода data(). Поплакал я немного, проштудировал документацию и программирую себе вздыхая о паскале. Живут же люди и
> и как-то не жалуются особо
Работает ведь и то счастье.
|