Inline vs CopyPast и способ передачи параметров в процедуры.

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Re: Inline vs CopyPast и способ передачи параметров в процед

Сообщение stikriz » 02.08.2012 19:23:50

Ask писал(а):constдля параметров типа string

Использовать var? :-)
Ask писал(а):не использовать constдля параметров [...], интерфейсов и объектов, а также записей, содержащих эти типыв качестве полей.

Это детские трудности непонимания указателей.
Короче, мнение очень спорное. Используйте const, особенно с типами string. Если проблемы с указателями, то есть очень много других интересных профессий.
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Inline vs CopyPast и способ передачи параметров в процед

Сообщение alexey38 » 02.08.2012 20:00:44

Ask писал(а):Это не так. К сожалению, с ключевым словом "const" в Паскале связан ряд заблуждений. На самом деле:
1) Ключевое слово "const" НЕ влияет непосредственно на способ передачи параметра -- параметр может быть передан как по ссылке,
так и по значению в зависимости от платформы, настроек оптимизации и т.д.
2) Чтобы гарантировать передачу по ссылке, следует использовать модификатор "constref", но он был реализован относительно недавно, и разработчики компилятора не рекомендуют его использовать без веской причины.
3) Ключевое слово "const" интерпретируется как обещание *от программиста компилятору*, что указанная переменная не поменяется *нигде в программе* в период выполнения функции/процедуры. Обратите внимание, что именно от программиста к компилятору, а не наоборот. Компилятор проверяет выполнение этого обещания только в простейших случаях. Если оно всё же будет нарушено, это может привести к очень трудно отлаживаемым ошибкам и падениям, особенно в случае refcounted типов, таких как строки и интерфейсы.
4) Разработчики языка принципиально не будут менять перечисленные выше пункты -- на этот счёт были долгие и бурные дискуссии, их позиция окончательна.

Таким образом, можно порекомендовать использовать префикс const осторожно, относиться к нему как к оптимизации,
и уж во всяком случае не расставлять бездумно где попало -- например, современные версии Lazarus больше не добавляют "const" автоматически к
параметру setter'а свойств объекта.
К модификаторам var и out перечисленные проблемы не относятся -- их можно свободно использовать там, где они нужны по смыслу
(не путая друг с другом, конечно).


Я бы сказал, что Ваше мнение довольно сомнительное по существу.

Во-первых, важно запомнить, что Вы пишите программу на языке высокого уровня не только и не сколько для компилятора, сколько для себя (для программиста). Компилятор - это машина, не для нее стараемся. Если программа не разовая, то программисту код читать еще 100 раз. И вот ради себя любимого, чтобы облегчить себе жизнь мы используем Const, префиксы, суфиксы и прочие вещи делающие код ясным и понятным.

Во-вторых, смысл Const не в ссылке, если нужна гарантированная ссылка, то пишем Var. Опитимизационный смысл Const в несоздании копии для строк и записей. Для числовых полей копия все же создается, т.к. трудоемкость передачи через стек ссылки и числа одинаковая, а внутри кода процедуры косвенная адрессация работает медленее. Так что в части оптимизации кода Const - это правильное решение.

Что касается нового "constref", то если честно, не понял зачем это сделали. Если ты используешь Const, то берешь на себя обязательство не менять поле. А если не менять поле, то зачем нужна гарантированная ссылка? Нужен указатель? Тогда используй Var или Pointer, будет яснее. Тут либо для совместимости с С, либо для запутывания логики, когда вроде бы Const, но можешь все же использовать не по назначению. Для обычного кода очевидно, что constref не нужно использовать, т.к. он скрывает ясность кода.

P.S. Не знаю точно, как делает FPC (для разных опций), но Дельфи при передаче строк как Proc(Const strPar:String), передает ссылку, и не делает копию строки. А Proc(strPar:String) должен сделать копию строки, т.к. меняя в процедуре strPar не должна изменяться строка в вызывающем коде.

Добавлено спустя 5 минут 21 секунду:
Re: Inline vs CopyPast и способ передачи параметров в процедуры.
iN0k писал(а):то есть шаманское изменение привело к интерисующему меня результату.
а шаманскому, по тому что для меня не очевидна.
может кто-нибудь разьяснить полученный результат?


Результат говорит о том, что inline - работает так, как требовалось. Он весь код вызываемой процедуры копирует в место вызова.

Что касается Вашего исходного вопроса:
Код: Выделить всё
procedure F1(prm:rMyRecord);
begin
    F0(@prm);
end;


То нужно сделать так:
Код: Выделить всё
procedure F1(Var prm:rMyRecord);inline;
begin
    F0(@prm);
end;


Тогда вызов F1 будет идентичен вызову F0 без дубляжа кода обработки из F0, но и без лишнего перевызова в F1.
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Inline vs CopyPast и способ передачи параметров в процед

Сообщение Ask » 03.08.2012 07:57:59

Как видим, заблуждения о том, как работает const, действительно широко распространены :)
Господа, Я согласен с тем, что Ваше описание -- это хорошая модель для модификатора const.
К сожалению, на самом деле const работает не так.
Я потратил немало нажатий на кнопки, пытаясь убедить разработчиков FPC сделать, как Вы предлагаете --
прочтите хотя бы тот трэд, что Я привёл, а таких было несколько.
Разработчики отказались (и у них есть свои основания, хотя Я с ними и не согласен).
Как Я уже говорил:
1) const даёт компилятору выбор относительно способа передачи параметра (например, записи передаются по ссылке либо по значению в зависимости от SizeOf и платформы). Таким образом, при использовании const программист должен внимательно следить, чтобы семантика кода не зависела от способа передачи.
2) const даёт компилятору возможность предполагать, что обозначенная переменная не изменится *нигде в программе*, а не только непосредственно
в текущей процедуре. В частности, refcounted типы c модификатором const не делают incref/decref! Если вдруг значение переменной, переданной в качестве параметра по const, изменится, программа упадёт с *очень* трудно отлавливаемым AV в *эпилоге процедуры*, т.е. вообще не в пользовательском коде. Поскольку модифицирующий код может находиться в другом модуле, быть написанным другим программистом в другое время, и вообще относиться к другому уровню приложения, эту ошибку можно предотвратить только одним способом -- не использовать const c refcounted типами.

Отдельно хочу сказать, что "если нужна гарантированная ссылка, то пишем var" -- это стилистически неправильно, поскольку смешивает понятия способа передачи параметра и необходимости его модификации. Правильно будет "если нужна гарантированная ссылка, *и мы планируем изменять переменную*, то пишем var, иначе пишем constref.
Ask
постоялец
 
Сообщения: 163
Зарегистрирован: 25.12.2008 03:51:37

Re: Inline vs CopyPast и способ передачи параметров в процед

Сообщение Kemet » 03.08.2012 15:20:39

Видимо это какое-то индивидуальное восприятие.
Ведь строки, объекты, интерфейсы и тд - изначально ссылочные типы, т.е., по сути, указатели. Поэтому в процедуру в качестве параметра передается не строка, объект и т.д, а типизированный указатель и именно к нему, к этому указателю, как параметру, и применяется модификатор const.
Понятно, что в таком случае, доступ только для чтения распространяется лишь на указатель, а не на содержимое экземпляра. Хотя я встречал реализации Паскаля, в которых конст честно обеспечивал доступ только для чтения для любых обращений к парамерту, как к lvalue.
Kemet
постоялец
 
Сообщения: 241
Зарегистрирован: 10.02.2010 19:28:32
Откуда: Временно оккупированная территория

Re: Inline vs CopyPast и способ передачи параметров в процед

Сообщение stikriz » 03.08.2012 16:23:39

Kemet писал(а): Хотя я встречал реализации Паскаля, в которых конст честно обеспечивал доступ только для чтения для любых обращений к парамерту, как к lvalue.

Для этого надо делать объекты на стеке.
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Inline vs CopyPast и способ передачи параметров в процед

Сообщение Kemet » 03.08.2012 16:30:59

stikriz, зачем на стеке? Это же контроль времени компиляции. Нет никакой разницы, в стеке или в куче.
Kemet
постоялец
 
Сообщения: 241
Зарегистрирован: 10.02.2010 19:28:32
Откуда: Временно оккупированная территория

Re: Inline vs CopyPast и способ передачи параметров в процед

Сообщение stikriz » 03.08.2012 16:42:22

Потому, что я могу скопировать адрес в другой поинтер, или вычислить его. А пометить область памяти как только для чтения и поймать прерывание процессора - это железобетонно.
Аватара пользователя
stikriz
энтузиаст
 
Сообщения: 612
Зарегистрирован: 15.03.2006 09:37:47

Re: Inline vs CopyPast и способ передачи параметров в процед

Сообщение Kemet » 03.08.2012 17:44:28

stikriz, мы о разных вещах говорим. Я имею ввиду контроль именно во время компиляции и именно над параметром, коим в данном случае является ссылка на экземпляр - её изменить ( если она конст ) нельзя.
То, что мы можем скопировать - это другое дело, хотя и здесь что-то можно на этапе компиляции отследить, атам, где неоднозначность - варнинги. А то, о чем Вы пишете нужно отслеживать в рантайме использую какую-либо реализацию механизма охраны экземпляра.
Kemet
постоялец
 
Сообщения: 241
Зарегистрирован: 10.02.2010 19:28:32
Откуда: Временно оккупированная территория

Re: Inline vs CopyPast и способ передачи параметров в процед

Сообщение alexey38 » 03.08.2012 18:11:10

Ask писал(а):Как видим, заблуждения о том, как работает const, действительно широко распространены :)
Господа, Я согласен с тем, что Ваше описание -- это хорошая модель для модификатора const.
К сожалению, на самом деле const работает не так.
Я потратил немало нажатий на кнопки, пытаясь убедить разработчиков FPC сделать, как Вы предлагаете --
прочтите хотя бы тот трэд, что Я привёл, а таких было несколько.
Разработчики отказались (и у них есть свои основания, хотя Я с ними и не согласен).
Как Я уже говорил:
1) const даёт компилятору выбор относительно способа передачи параметра (например, записи передаются по ссылке либо по значению в зависимости от SizeOf и платформы). Таким образом, при использовании const программист должен внимательно следить, чтобы семантика кода не зависела от способа передачи.
2) const даёт компилятору возможность предполагать, что обозначенная переменная не изменится *нигде в программе*, а не только непосредственно
в текущей процедуре. В частности, refcounted типы c модификатором const не делают incref/decref! Если вдруг значение переменной, переданной в качестве параметра по const, изменится, программа упадёт с *очень* трудно отлавливаемым AV в *эпилоге процедуры*, т.е. вообще не в пользовательском коде. Поскольку модифицирующий код может находиться в другом модуле, быть написанным другим программистом в другое время, и вообще относиться к другому уровню приложения, эту ошибку можно предотвратить только одним способом -- не использовать const c refcounted типами.

Отдельно хочу сказать, что "если нужна гарантированная ссылка, то пишем var" -- это стилистически неправильно, поскольку смешивает понятия способа передачи параметра и необходимости его модификации. Правильно будет "если нужна гарантированная ссылка, *и мы планируем изменять переменную*, то пишем var, иначе пишем constref.


Как я писал ранее назначение Const именно информативное и для оптимизации кода, где компилятор сам решает какие параметры каким образом передавать, через стек, регистры или ссылки.

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

Про ситуации типа "Если вдруг значение переменной, переданной в качестве параметра по const, изменится, программа упадёт с *очень* трудно отлавливаемым AV в *эпилоге процедуры*, т.е. вообще не в пользовательском коде." - это как раз все элементарно определяется, т.к. программа хотя бы падает.
Намного хуже, когда ошибка функциональная, что приводит не к падению, а к искажению результата. То есть декларация процедуры (метода) не соответствует фактическому функционалу. И здесь кроме ясности кода мало, что может помочь.

А насчет constref, то я так и не смог придумать реального примера, когда нужна именно ссылка, но менять мы ничего не будем. Кроме хаккерских целей ничего на ум не приходит. Ну разве что в многозадачной постановке, но тут без атомарных операций и блокирово все равно ничего не будет работать, так что назначение constref так и не понял.
alexey38
долгожитель
 
Сообщения: 1627
Зарегистрирован: 27.04.2011 19:42:31

Re: Inline vs CopyPast и способ передачи параметров в процед

Сообщение Ask » 04.08.2012 11:53:09

Намного хуже, когда ошибка функциональная, что приводит не к падению, а к искажению результата

Ну, const на refcounted типах вызывает обращение к освобождёной области памяти,
так что там как повезёт -- обычно падает, но может и неправильный результат получить.

не смог придумать реального примера, когда нужна именно ссылка, но менять мы ничего не будем

Код: Выделить всё
procedure MyCopy(out ADest: TMyBigRec; constref ASrc: TMyBigRec); begin if @ADest = @ASrc then exit; ...
Ask
постоялец
 
Сообщения: 163
Зарегистрирован: 25.12.2008 03:51:37

Re: Inline vs CopyPast и способ передачи параметров в процед

Сообщение runewalsh » 30.03.2013 23:30:01

А насчет constref, то я так и не смог придумать реального примера

Он нужен для совместимости с сишными либами.
Пример: http://newtondynamics.com/wiki/index.ph ... rldRayCast
p0 и p1 — указатели на трёхмерные векторы. Напрашивается вариант с var p0, p1: NewtonVec3. Но var-параметры нельзя вычислять на месте, а загромождать код не хочется. Constref просто сообщает компилятору, что ссылка на rvalue — фактически временную переменную на стеке — тоже подойдёт, и человеческий код вида
Код: Выделить всё
NewtonWorldRayCast(world, NewtonVec3(camera.pos), NewtonVec3(camera.pos + MaxDistance * camera.dir), ...).

становится валиден.
Аватара пользователя
runewalsh
энтузиаст
 
Сообщения: 579
Зарегистрирован: 27.04.2010 00:15:25

Пред.

Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 13

Рейтинг@Mail.ru