Тернарный условный оператор в 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;

Но есть пару нюансов:

  1. типами аргументов у нас могут быть только примитивные Integer, Int64, Double и string. С объектами или перечисляемыми типы облом 😦
  2. Значения аргументов функции вычисляются перед её вызовом, поэтому в отличии от стандартного условного оператора 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.

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

  1. Если вычисления в аргументах IfThen довольно сложные или запись IfThеn не вмещается на одну строчку, перепишите этот код через стандартный блок if-then-else.
  2. Никогда, никогда не делайте вложенные вызовы IfThen!Так писать нельзя!
    N := IfThen(A < 0, -1, IfThen(A = 0, 0, 1));
    

    Потом не разгребётесь.

Используйте IfThen почаще, но с умом и тогда ваш код станет лучше!

Один комментарий

  1. Аноним

    Спс добрый человек. Пока в в пхп не начал юзать тернарную запись, не подумал бы что такое есть в делфи. Теперь разгуляюсь)

  2. Денис Грибанов

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

Оставьте комментарий