Должна ли переменная быть инициализирована перед вызовом функции?

Когда я вызываю функции для получения значения, я обычно инициализирую переменную на случай, если функция не работает или ничего не возвращает, и я хочу избежать работы с неинициализированной переменной. Я делаю то же самое для строки, целого числа или любого другого типа.

Пример для целочисленных переменных:

vPropValue := 0;
vPropValue := GetPropValue(vObject,'Height');

IF vPropValue > 0 Then
...

это наиболее распространенный способ, которым я его использую.

Я знаю, что мог бы использовать:

If GetPropValue(vObject,'Height') > 0 Then
...

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

То же самое для строки (хотя я знаю, что локальные строки инициализируются пустой строкой, а целые числа не могут содержать какое-либо значение)

vName := '';
vName := GetObjectName(vObject,'ObjectName');

IF Trim(vPropStrValue) <> '' Then
...

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

Я пытаюсь понять, почему это нежелательно и как этого избежать.

ИЗМЕНИТЬ

Вот пример, когда функция не возвращает правильное значение или 0:

function GetValue(vType:integer):integer;
begin
   if vType=1 then
    Result:=100
   else if (vType>2) and (vType<=9) then
     Result:=200;

end;

procedure TForm1.Button1Click(Sender: TObject);
var vValue:integer;
begin

  vValue:=GetValue(11);
  Button1.Caption:=IntToStr(vValue);

end;

В этом случае значение, возвращаемое функцией, представляет собой случайное число.

В этом случае инициализация представляется допустимым подходом. ИЛИ НЕТ?

РЕДАКТИРОВАТЬ 2:

Как указал Дэвид в своем ответе, правильно, было предупреждение

[dcc32 Warning] Unit1.pas(33): W1035 Return value of function 'GetValue' might be undefined

но, я проигнорировал это, без всякой причины, просто не посмотрел туда. Поскольку он позволил мне скомпилировать его, я подумал, что все в порядке. Итак, я искал предупреждение и «исправил» довольно много функций, у которых была похожая проблема, из-за всех IF Результат мог быть не определен.

РЕДАКТИРОВАНИЕ 3 И ЗАКЛЮЧЕНИЕ:

Я надеюсь, что это добавит объема вопросов и объяснений:

Возможно, пример другого поворота, который я использую в большинстве своих функций, также объясняет, почему я думал, что моя инициализация переменной необходима, заключается в том, что я не был уверен, что мои функции будут вести себя правильно все время, особенно в случае вложенной функции . Моты из них до сих пор установлены так:

function GetProperty(vType:integer):integer;
begin
  Try
    if vType = 99 then
      Result:=GetDifferentProperty(vType)// <-- Call to another Function, that could return whatever...
    else
    begin
       if vType=1 then
          Result:=100
       else if (vType>2) and (vType<=9) then
         Result:=200;
    end;
  except
  end;
end;

Теперь я обращаюсь к этим Try Except End;, но некоторым функциям уже 10 лет, и ожидать, что они будут работать на 100%, основываясь на моем опыте того времени, не стоит полагаться.

Как единственный разработчик в этом проекте, я предполагаю, что должен доверять своим функциям (и остальной части моего кода), но я не могу представить, что в среде с несколькими разработчиками все функции настроены правильно.

Итак, мой вывод: поскольку я не позаботился об основах - правильно спроектированных функциях, мне нужны все эти проверки (инициализация переменных, Try Except строк...) и, возможно, некоторые другие ненужные вещи.


person Mike Torrettinni    schedule 25.11.2015    source источник
comment
Re: редактировать № 1 - инициализация является допустимым подходом, но ее следует переместить ВНУТРИ функции. pastebin.ca/3272345   -  person Arioch 'The    schedule 26.11.2015
comment
Я почти отклонил это как еще один дубликат инициализации переменных. Но на самом деле это был хороший вопрос. Вы прилагаете соответствующие усилия; и есть некоторые ценные идеи, которые можно получить даже для опытных разработчиков Delphi. +1   -  person Disillusioned    schedule 26.11.2015
comment
Есть некоторые функции RTL, которые вызывают исключение, когда ввод неверен. Пример StrToInt(). Чтобы использовать их правильно, вы должны использовать кадр try/except, где вы обрабатываете случай исключения. В обработчике исключения вы можете установить значение после вызова функции (или сделать что-то совершенно другое). Как правило, вам следует избегать этой конструкции, если есть альтернативы. Код может быть трудночитаемым, а исключения могут снизить производительность. В приведенном примере предпочтительны такие альтернативы, как StrToIntDef или TryStrToInt.   -  person LU RD    schedule 26.11.2015
comment
Я не понимаю проглотить все обработчики исключений в вашем последнем редактировании. Это очень плохая практика. Кстати, я впечатлен вашим желанием привести код в порядок. Это очень хороший знак!   -  person David Heffernan    schedule 26.11.2015
comment
ваша функция редактирования 3 по-прежнему неверна, поскольку она будет давать значения мусора для некоторых входных значений, например, мусор будет предоставлен, когда vType=2. Вы должны сделать значение по умолчанию ВНУТРИ функции, как я описал в моей ссылке выше. См. обновленный образец pastebin.ca/3272690.   -  person Arioch 'The    schedule 26.11.2015
comment
@Arioch'The Correct, Edit 3 является примером моего текущего «стиля» большинства моих функций. Зная эти ответы, я начну вносить изменения в сотни из них. Служба Pastebin.ca, похоже, сейчас не работает...   -  person Mike Torrettinni    schedule 26.11.2015
comment
@MikeTorrettinni возьми это из Google! webcache.googleusercontent.com/   -  person Arioch 'The    schedule 27.11.2015


Ответы (4)


Предполагая, что vPropValue является локальной переменной, тогда этот код

vPropValue := 0;
vPropValue := GetPropValue(vObject,'Height');

неотличим от

vPropValue := GetPropValue(vObject,'Height');

Более простой пример может быть таким:

i := 0;
i := 1;

Какой смысл присваивать 0 i, а затем сразу присваивать 1 i? Так что вы точно никогда не напишете такое. Вы бы написали:

i := 1;

В вашем коде в верхней части этого ответа вы дважды назначаете одну и ту же переменную. Значение, присвоенное в первом присвоении, немедленно заменяется значением, присвоенным во втором присвоении. Поэтому первое присвоение бессмысленно и должно быть удалено.

Второй пример немного сложнее. Предполагая, что ваши функции написаны правильно и всегда присваивают возвращаемое значение, а vName является локальной переменной, тогда

vName := '';
vName := GetObjectName(vObject,'ObjectName');

неотличим от

vName := GetObjectName(vObject,'ObjectName');

Причина, по которой я добавил дополнительную оговорку, связана с особенностью реализации возвращаемых функций значений, обсуждаемой ниже. Разница между этим случаем и случаем выше заключается в типе возвращаемого значения. Здесь это управляемый тип string, тогда как в первом примере это простой тип Integer.

Опять же, учитывая оговорку о том, что функция всегда присваивает возвращаемое значение, первое присваивание бессмысленно, поскольку значение немедленно заменяется. Удалите это первое задание.


Что касается функции в вашем редактировании, компилятор предупредит вас о ее ошибочной реализации, если вы включите подсказки и предупреждения. Компилятор скажет вам, что не все пути кода возвращают значение.

function GetValue(vType:integer):integer;
begin
  if vType=1 then
    Result:=100
  else if (vType>2) and (vType<=9) then
    Result:=200;
end;

Если ни одно из условий не выполняется, то переменной результата не присваивается никакого значения. Эта функция должна быть:

function GetValue(vType:integer):integer;
begin
  if vType=1 then
    Result:=100
  else if (vType>2) and (vType<=9) then
    Result:=200
  else
    Result:=0;
end;

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


Причина, по которой ваше двойное присваивание иногда кажется вам полезным, связана с причудой реализации возвращаемых значений функций в Delphi. В отличие от почти всех других языков, возвращаемое значение функции Delphi для некоторых более сложных типов на самом деле является параметром var. Итак, эта функция

function foo: string;

на самом деле, семантически, то же самое, что и это:

procedure foo(var result: string);

Это действительно странное решение дизайнеров Delphi. В большинстве других языков, таких как C, C++, C#, Java и т. д., возвращаемое значение функции похоже на параметр по значению, передаваемый от вызываемого объекта к вызывающему.

Это означает, что вы можете, если хотите быть извращенными, передавать значения в функцию через ее возвращаемое значение. Например, рассмотрим этот код:

// Note: this code is an example of very bad practice, do not write code like this

function foo: string;
begin
  Writeln(Result);
end;

procedure main;
var
  s: string;
begin
  s := 'bar';
  s := foo;
end;

Когда вы вызываете main, он выводит bar. Это довольно странная деталь реализации. Вы не должны полагаться на это. Позвольте мне повторить. Вы не должны полагаться на это. Не привыкайте инициализировать возвращаемые значения на месте вызова. Это приводит к неподдерживаемому коду.

Вместо этого следуйте простому правилу обеспечения того, чтобы возвращаемое функцией значение всегда присваивалось функцией и никогда не считывалось до того, как оно было присвоено.


Более подробная информация о реализации возвращаемых функцией значений приведена в документации, где я выделил:

Следующие соглашения используются для возврата значений результата функции.

  • Порядковые результаты возвращаются, когда это возможно, в регистр ЦП. Байты возвращаются в AL, слова возвращаются в AX, а двойные слова возвращаются в EAX.
  • Реальные результаты возвращаются в верхний регистр стека сопроцессора с плавающей запятой (ST(0)). Для результатов функции типа «Валюта» значение в ST(0) масштабируется на 10000. Например, значение «Валюта» 1,234 возвращается в ST(0) как 12340.
  • Для строки, динамического массива, указателя метода или вариантного результата результат будет таким же, как если бы результат функции был объявлен как дополнительный параметр var после объявленных параметров. Другими словами, вызывающий объект передает дополнительный 32-битный указатель, указывающий на переменную, в которой должен быть возвращен результат функции.
  • Int64 возвращается в EDX:EAX.
  • Результаты указателя, класса, ссылки на класс и указателя процедуры возвращаются в EAX.
  • Для результатов static-array, record и set, если значение занимает один байт, оно возвращается в AL; если значение занимает два байта, оно возвращается в AX; и если значение занимает четыре байта, оно возвращается в EAX. В противном случае результат возвращается в виде дополнительного параметра var, который передается функции после объявленных параметров.
person David Heffernan    schedule 25.11.2015
comment
Очень хорошее понимание, спасибо за подробное объяснение. Правильно, предупреждение было, но я его не заметил. - person Mike Torrettinni; 26.11.2015
comment
Действительно, интересная реализация возврата функции, спасибо, что указали на это. Это заставляет меня задаться вопросом: если мы вызываем функцию как процедуру, не присваивая результат где-либо, создает ли компилятор какую-то фиктивную переменную на стороне вызывающей стороны и преобразует, например, showModal в _somevar:=showModal, чтобы было место, куда поместить результат? - person Yuriy Afanasenkov; 26.11.2015
comment
@Yuriy Компилятор не создает фиктивную переменную, когда вы вызываете функции как процедуры. На самом деле это работает наоборот: функция всегда возвращает значение в специальном месте. Если вы вызываете это как процедуру, возвращаемое значение просто игнорируется, и больше ничего не происходит (кроме очистки управляемого типа). Однако если вы вызываете функцию как функцию, компилятор копирует возвращаемое значение в выбранное вами место после возврата функции. (ПРИМЕЧАНИЕ, компилятор может выполнять определенные оптимизации, которые изменяют что-то в особых случаях, но в этом суть.) - person Disillusioned; 26.11.2015
comment
@CraigYoung, что в основном означает то же самое. Компилятор создает фиктивную переменную, просто не всегда копирует значение из этой фиктивной переменной. И эта неявная фиктивная переменная (для управляемых типов, таких как интерфейсы, динамические массивы, строки) на сайте вызывающей стороны — это то, что обеспечивает приемы в стиле RAII, такие как deltics.co.nz/blog/posts/404 - person Arioch 'The; 26.11.2015
comment
@CraigYoung Я экономил на деталях в предыдущих ответах. Прочитайте цитату из документа, которая теперь включена. Обратите особое внимание на часть о дополнительном параметре var. - person David Heffernan; 26.11.2015
comment
@YuriyAfanasenkov с вашим конкретным примером ( ShowModal ), хотя вы используете тип возврата int32, и компилятору нечего делать: этот тип - просто проверьте соглашение о вызовах по умолчанию Delphi - возвращается через регистр EAX процессора, который всегда есть для этой цели, и ничего не нужно дополнительно выделять. - person Arioch 'The; 26.11.2015
comment
@YuriyAfanasenkov Действительно существуют фиктивные переменные, но только для определенных сложных типов, как описано в цитате из документа, которую я добавил к ответу. - person David Heffernan; 26.11.2015
comment
@Arioch'Я пытался подчеркнуть, что манекен не создан для особого случая вызова функции как процедуры, а всегда есть. - person Disillusioned; 26.11.2015
comment
@DavidHeffernan Документы Delphi, как обычно, устарели .... Ни одного упоминания о RAX в режиме компиляции AMD64 :-/ - person Arioch 'The; 26.11.2015
comment
@Arioch'The True. Платформа ABI соблюдается, за некоторыми исключениями. В частности, обработка возвращаемых значений! - person David Heffernan; 26.11.2015
comment
@CraigYoung Фиктивная переменная создается в тех случаях, когда возвращаемое значение передается как параметр var. - person David Heffernan; 26.11.2015
comment
@DavidHeffernan, это одна из причин, по которой я считаю, что человеку следует попробовать программирование на ассемблере для Delphi - чтобы понять основы построения лесов. Он не может просто запомнить документы, потому что документы плохие. Кто-то лучше понимает, что происходит, и может смотреть и видеть с помощью инструментов отладки, когда его ожидания не оправдались. // лично, когда мне нужно было сделать ассемблер для xe2 x64, я точно сделал функции purepascal и посмотрел на вызывающие/завершающие процессы, потому что компилятор, а не отсутствующие документы, является здесь высшим авторитетом - person Arioch 'The; 26.11.2015
comment
@DavidHeffernan w.r.t. это ужасная слабость Delphi - мы должны понимать, что потоковый анализ в Delphi очень ограничен. Классическая проблема: ValueFlag := false; ..... if ... then begin ... HeavyComplexValue := ...; ValueFlag := true; end; ..... if ValueFlag then .... using(HeavyComplexValue); - и здесь компилятор скажет как неинициализированное значение, которое НЕПРАВИЛЬНО. Поэтому, если вы предпочитаете превратить это конкретное предупреждение в серьезную ошибку, вы можете сделать это в параметрах вашей IDE/проекта. Но, учитывая ограничения Delphi, я бы не стал делать ставку на то, что компилятор ВСЕГДА определяет, установлено ли значение результата или нет. - person Arioch 'The; 26.11.2015
comment
@David Да, ваше добавление соглашений о возврате является очень полезным разъяснением того, когда создается фиктивная переменная и когда используется фиксированное местоположение. В общем, я бы сказал, что этот вопрос оказался намного интереснее, чем может показаться на первый взгляд. - person Disillusioned; 26.11.2015
comment
@CraigYoung Действительно. Спасибо, что побудили меня быть более точным. - person David Heffernan; 26.11.2015
comment
Итак, если в EAX возвращаются int32, то если функция ничего не присваивала результату, в EAX может быть какой-то мусор, который будет скопирован в переменную при вызове value:=func(...) и в этом случае действительно нет смысла инициализировать значение раньше, это не спасет его от хранения мусора после вызова func(...). Единственный способ при инициализации имеет значение, когда результат передается как дополнительный параметр var. - person Yuriy Afanasenkov; 26.11.2015
comment
@YuriyAfanasenkov Это сложнее. Значение, которое оказывается в EAX, может быть хорошо определено. Это то, что случилось там до того, как был сделан звонок. Часто это будет первый параметр, передаваемый функции. Так что это может быть не мусор, и код вполне может вести себя так, как задумано, совершенно случайно. Затем программа может сломаться из-за небольших изменений, таких как включение/выключение оптимизации компилятора. - person David Heffernan; 26.11.2015
comment
@DavidHeffernan ... или, например, переключиться на платформу AMD64, где Delphi переключится на регистры RCX, RDX, R8, R9 и, таким образом, не заполнит RAX / EAX параметром in. В принципе, Юрий прав, в его примере EAX действительно содержит мусор на выходе, потому что мусором является все, что вы не преднамеренно поместили туда. Пока вы не писали хакерский код, зависящий от причуд, преобразование in-parameter в ret-value является непреднамеренной случайностью, а значит, мусором. - person Arioch 'The; 26.11.2015
comment
@Arioch'Я просто хочу сказать, что иногда этот мусор может быть случайно четко определен таким образом, что маскирует неработающую реализацию функции. - person David Heffernan; 26.11.2015

Следующий код (А)

vPropValue := 0;
vPropValue := GetPropValue(vObject,'Height');

неотличим от (В)

vPropValue := GetPropValue(vObject,'Height');

Вопрос о том, "правильно ли написано" GetPropValue, совершенно неуместен.

Давайте рассмотрим, что произойдет, даже если вы напишете GetPropValue неправильно.

function GetPropValue(AObject: TObject; AStr: String): Integer;
begin
  if AStr = 'Hello' then Result := 5;
end;

Как вы знаете, когда вход AStr отличается от «Hello», результат функции будет в значительной степени случайным. (Ради обсуждения предположим, что он вернет -42.)

Блок кода (A) сделает следующее:

  • Установите vPropValue на 0
  • Затем установите vPropValue на - 42

Блок кода (B) просто немедленно установит vPropValue в -42.

СОВЕТ. Нет смысла писать бесполезную строку кода только потому, что вы беспокоитесь, что могли допустить ошибку в вызываемой вами функции.
Во-первых, как указывает Дэвид, вы можете избежать многих ошибок, просто обращая внимание к вашим подсказкам и предупреждениям компилятора. Во-вторых, такое "параноидальное" кодирование просто приводит к более расточительному коду, потому что теперь вы должны начать рассматривать недопустимые значения как возможные результаты.
Ситуация становится еще хуже, когда однажды ваше "безопасное значение" на самом деле < em>допустимое значение. Например. как бы вы определили разницу между «0 по умолчанию» и «правильно возвращенный 0»?

Не усложняйте программирование искусственно, раздувая код ненужной избыточностью.


Примечание

Есть несколько особых ситуаций, когда код может вести себя по-разному. Но вы в любом случае должны избегать проектов, которые приводят к таким ситуациям, потому что они значительно усложняют поддержку кода.

Я упомянул их исключительно для полноты картины, приведенный выше совет остается в силе.

1) если vPropValue реализовано как свойство, установщик может иметь побочные эффекты, вызывающие другое поведение. Хотя в свойствах нет ничего плохого, когда они делают неожиданные вещи, у вас возникают серьезные проблемы.

2) если vPropValue является полем класса (или, что еще хуже, глобальной переменной), то (A) и (B) могут вести себя по-разному, но только если< /strong> GetPropValue вызывает исключение. Это связано с тем, что исключение предотвратит присвоение результата. Обратите внимание, что этого следует избегать, за исключением особых случаев, потому что это затрудняет понимание того, что делает ваш код.

И на самом деле это то, что делает гораздо более важным избегать избыточных инициализаций. Вы хотите, чтобы ваш код особого случая отличался от остальных.

person Disillusioned    schedule 26.11.2015
comment
Вопрос о том, правильно ли написан GetPropValue, совершенно неактуален. True для неуправляемых типов результатов, которые возвращаются в регистры. Я упустил этот нюанс в своих ранних версиях, но теперь исправил это упущение. Рассмотрите типы управляемых результатов, в которых значение результата передается как параметр var. В частности, документ цитирует мой ответ и пример кода, который передает значение функции через ее значение результата. - person David Heffernan; 26.11.2015
comment
Что касается побочного примечания 2, то помимо исключений следует рассмотреть еще один случай. То есть, если переменная видна другому потоку. Я опустил все эти нюансы, потому что они являются крайними случаями, поэтому я уверен, что вы поместили их в качестве примечания. - person David Heffernan; 26.11.2015
comment
@David Да, это просто примечание. Код OP не показывает, что переменные являются локальными, поэтому я решил, что его стоит поднять. И я думал об упоминании тем, но решил не делать этого, потому что чувствовал, что это немного расширит рамки. - person Disillusioned; 26.11.2015
comment
подобное параноидальное кодирование просто приводит к более расточительному коду Я полностью согласен и голосую за :) - person fantaghirocco came to Rome; 26.11.2015
comment
Спасибо @CraigYoung, теперь, читая весь этот замечательный контент в ответах, я согласен, что это не имеет значения, правильно ли написана функция или нет, но, как я отметил в Edit 3, это была комбинация незнания того, как все работает, и понимания (или ожидая?), что функция может дать сбой и, возможно, не вернет никакого значения. - person Mike Torrettinni; 26.11.2015

Удаление моих советов из комментариев верхнего уровня на случай сбоя Pastebin

function GetValueUpdate3(vType:integer):integer;
begin
// with SOME types like Integer you can use Pascal case-block instead of error-prone many-ifs-ladder

  case vType of 

    99:   Result:=GetDifferentProperty(vType);// <-- Call to another Function, that could return whatever...
    1:    Result:=100;
    3..9: Result:=200;

    else Result := 12345; // initialization with safe default value for illegal input like vType=2  

  end; // case-block
end;

function GetValueUpdate3e(vType:integer):integer;
begin
  case vType of

    99:   Result:=GetDifferentProperty(vType);// <-- Call to another Function, that could return whatever...
    1:    Result:=100;
    3..9: Result:=200;

    else raise EInvalidArgument.Create('prohibited value - GetValue( ' + IntToStr(vType) +' )' );
      // runtime eror when vType = 2 or any other illegal input
  end;
end;


function GetValueUpdate1(vType:integer):integer;
begin
  Result := 12345; // initialization with safe default value;

  if vType=1 then Exit(100); // special value for special case #1

  if (vType>2) and (vType<=9) then Exit(200); // special value for special case #2

  // exit with default value
end;

procedure TForm1.Button1Click(Sender: TObject);
var vValue:integer;
begin

  vValue:=GetValue(11);
  Button1.Caption:=IntToStr(vValue);

end;

// http://stackoverflow.com/questions/33927750
person Arioch 'The    schedule 26.11.2015
comment
Спасибо, особенно за указание на использование «Выход (код)», я использую его только один раз во всем своем коде. Пора переосмыслить и это. - person Mike Torrettinni; 27.11.2015
comment
Это не такая уж хорошая идея. В итоге вы получите смесь exit(.._) и Result := , что, на мой взгляд, часто больше сбивает с толку, чем приносит пользу. - person David Heffernan; 28.11.2015
comment
Exit(code) — это ярлык для специального случая мгновенного выхода. Ярлык для утомительного begin/Result:=/exit/end Использовать его или нет — это личное дело каждого. В зависимости от структуры функции. Если у функции нет особых случаев, то нет смысла использовать этот параметризованный выход. Даже то, что Delphi ввела переменную Result — это хорошо или нет? Он предусматривает использование Result как обычной переменной, хранящей промежуточные значения. Может быть, само по себе использование переменной Result, изобретенной Delphi, плохо, и нам следует вернуться к Pascal? - person Arioch 'The; 28.11.2015
comment
@DavidHeffernan ниже есть ответ Александра Бальцера - и он не использует идею особых случаев, поэтому, когда он кодирует функцию, функционально аналогичную моей функции Upd1, он структурирует ее как лестницу if со всеми параметрами, имеющими аналогичную семантическую категорию. И значение по умолчанию там идет последним в строке (что лично мне не нравится). И моя функция использует другую семантику, она использует предварительное назначение значения по умолчанию (что может быть менее эффективным с точки зрения процессора) и набор изолированных особых случаев, а не цепочку. Но функционально они одинаковы - дело в семантике - person Arioch 'The; 28.11.2015
comment
Это просто мое личное мнение, что exit(...) мало что дает. - person David Heffernan; 28.11.2015

Вы можете использовать утверждения, чтобы проверить правильность ввода. Утверждения очень помогают в поиске логических ошибок в вашем коде.

Использование утверждений заставляет вас думать о допустимых и недопустимых входных данных и помогает писать лучший код. Включение и отключение утверждений во время компиляции осуществляется с помощью компилятора \$C или \$ASSERTIONS (глобальный переключатель).

В вашем примере функция GetValue может использовать утверждение следующим образом:

function GetValue(vType:integer):integer;
begin
   Assert((vType >= 1) and (vType <=9), 'Invalid input value in function GetValue');

   if vType=1 then
    Result:=100
   else if (vType>2) and (vType<=9) then
     Result:=200
   else Result := 0; // always catch the last else!
end;

Кроме того, каждый if-оператор должен включать финальный else! (По-моему ВСЕГДА!)

person Alexander Baltasar    schedule 27.11.2015
comment
Спасибо, я уже так много узнал из всех этих ответов здесь и сейчас о Assert. - person Mike Torrettinni; 27.11.2015
comment
Хе-хе-хе. Вы по-прежнему пропустили неверный случай vType=2 в своем утверждении. Майк, эти утверждения могут познакомить вас с такими общими понятиями, как c2.com/cgi/wiki?DefensiveProgramming /// c2.com/cgi/wiki?DesignByContract /// c2.com/cgi/wiki?DesignByContractAssertionsVsUnitTestsVsTypes - person Arioch 'The; 28.11.2015
comment
Хороший вопрос, Arioch 'The 9. Вот почему важно всегда ловить последнее ELSE ;-) Я немного удивлен, что прошло так много времени, прежде чем кто-то указал на неполное утверждение :-) - person Alexander Baltasar; 29.11.2015
comment
@AlexanderBalzer в последнюю очередь или всегда устанавливайте Результат первым, верно? Result := 0; в качестве первой строки... - person Mike Torrettinni; 29.11.2015