Тернарный условный оператор в Delphi/Pascal через функцию IfThen
Очень часто в коде мы пишем вот обычные конструкции if-then-else
внутри которых присваиваем переменной значение.
Для примера напишем простую функцию определяющей минимальное число:
function Min(A, B: Integer): Integer; var Min: Integer; begin if A < B then Min := A else Min := B; Result := Min; end;
А ведь очень часто таких вот конструкций в коде становится много, и они отнимают очень много места (аж четыре строчки!) и внимания у нас при том что они очень просты. Некоторые программисты записывают таки условия в одну строчку:
function Min(A, B: Integer): Integer; var Min: Integer; begin if A < B then Min := A else Min := B; Result := Min; end;
Но такая запись нарушает стандарт стилевого оформления кода и является очень нежелательной.
При этом имя переменной в которую мы записываем значение всё равно дублируется, это мелочь, но неприятно.
Так вот, в старом, добром, вечном, угрюмом и бесчеловечном Си для таких конструкций ввели специальный синтаксис: тернарный условный оператор.
Имеет он такую запись:
переменная = булево_выражение ? значение_переменной_если_выражение истинно : значение_если_ложь;
Вот так можно переписать нашу функцию на Си с его использованием:
int min(int a, int b) { int min; min = (a < b) ? a : b; return min; }
Тернарный условный оператор хорош не только тем что он компактнее, но и тем, что он более точно передаёт смысл кода, улучшая его читабельность.
Впервые он появился ещё в Алголе — праязыке всех современных языков, который успешно ввёл понятие структурного программирования. Паскаль это вообщем то и есть упрощённый Алгол, но вот тернарный оператор он почему то не унаследовал 😦
Зато практически все другие современные языки программирования, которые унаследовались от Си, сохранили синтаксис этого оператора нетронутым, а это: C++, JavaScript (ECMAScript), Objective-C, C#, D, Java, PHP, Perl.
В языках программирования, где такой радости как тернарный условный оператор нет, есть стандартные функции для его имитации.
В Delphi это функция IfThen, о которой как я заметил многие дельфисты не знают.
// Объявленные в стандартном юните Math function IfThen(ACondition: Boolean; ATrue: Integer; AFalse: Integer = 0): Integer; function IfThen(ACondition: Boolean; ATrue: Double; AFalse: Double = 0.0): Double; // Объявленные в стандартном юните StrUtils function IfThen(ACondition: Boolean; ATrue: string; AFalse: string = ''): string;
Её описание из хелпа:
Conditionally returns one of two specified values.
IfThen
checks the expression passed as ACondition
and returns ATrue
if it evaluates to true, or AFalse
if it evaluates to false. If the AFalse
parameter is omitted, IfThen
returns 0
or an empty string when ACondition
evaluates to False
.
Теперь можно переписать наш пример нахождения минимального числа так:
function Min(A, B: Integer): Integer; var Min: Integer; begin Min := IfThen(A < B, A, B); Result := Min; end;
Но есть пару нюансов:
- типами аргументов у нас могут быть только примитивные
Integer
,Int64
,Double
иstring
. С объектами или перечисляемыми типы облом 😦 - Значения аргументов функции вычисляются перед её вызовом, поэтому в отличии от стандартного условного оператора
if-then-else
у произойдёт вычисление всех его веток и это может вызвать ошибку.
Приведу пример, пользователь задал в полеEdit1
высоту формыForm1
. Мы берём строковое значение поляEdit1
, преобразовываем его вInteger
и задаём в качестве высоты формы. Если полеEdit1
пустое задаём форме стандартную высоту в400
пикселей.Вот реализация через
IfThen
:var FormHeight: Integer; begin FormHeight := IfThen(Edit1.Text '', StrToInt(Edit1.Text), 400); Form1.Height := FormHeight; end;
Во время выполнения если мы оставим
Edit1
пустым мы неожиданно получим исключение «Ошибка: пустая строка не есть число». Всё это горе нам потому, что программа сперва пытается вычислить значения передаваемых аргументов, т.е. преобразовать пустую строку в числоStrToIn('')
, а только потом вызываетIfThen
. Это никак не объехать, так что прийдётся написать по старинке через блокif-then-else
.
Кроме знаний этих нюансов, вам так же стоит запомнить два простых правила улучшения читаемости вашего кода:
- Если вычисления в аргументах
IfThen
довольно сложные или записьIfThеn
не вмещается на одну строчку, перепишите этот код через стандартный блокif-then-else
. - Никогда, никогда не делайте вложенные вызовы
IfThen
!Так писать нельзя!N := IfThen(A < 0, -1, IfThen(A = 0, 0, 1));
Потом не разгребётесь.
Используйте IfThen почаще, но с умом и тогда ваш код станет лучше!
автор, вы открываете мне глаза на программирование… :)спасибо за статью
Спс добрый человек. Пока в в пхп не начал юзать тернарную запись, не подумал бы что такое есть в делфи. Теперь разгуляюсь)
Вообще-то тернарный оператор (а не функция IfThen) в delphi возможен. Просто надо вместо значений передавать анонимные функции, которые возвращают эти значения. Правда, из-за громоздкости такой подход представляет ценность исключительно академическую.