Есть ли в Delphi условный оператор или он когда-либо будет? - PullRequest
32 голосов
/ 21 января 2010

Я держал руки от Дельфи слишком долго, наверное; За последние пару лет я много занимался Java и PHP. Теперь, когда я вернулся к выполнению небольшой работы в Delphi, я понял, что действительно скучаю по условному оператору, который поддерживается и Java, и PHP.

На скольких местах вы найдете такие строки в ваших программах на Delphi?

var s : string;
begin
  ...<here the string result is manipulated>...

  if combo.Text='' then
      s := 'null'
    else
      s := QuotedStr(combo.Text);

  result := result + s;
end;

где простой

result := result + (combo.text='')?'null':quotedStr(combo.text);

будет достаточно. Что мне нравится в этом, так это то, что он не только сокращает код, но и избегает объявления некоторой вспомогательной переменной s:string.

Почему условные операторы не являются частью Delphi и будут ли они когда-либо поддерживаться? Я заметил, что для версии Delphi 2009 (generics) было сделано несколько языковых расширений, так почему бы не добавить эту функцию?

Ответы [ 11 ]

41 голосов
/ 21 января 2010

Такой оператор не является частью текущей версии Delphi, потому что он не был частью предыдущей версии, и спрос был недостаточно велик, чтобы оправдать стоимость его добавления. (Вы найдете, что это объяснение применимо к лотам функций, которые вы хотели бы иметь в лотах продуктов.)

Delphi предоставляет набор IfThen функций в блоках Math и StrUtils, но у них есть прискорбное свойство оценивать оба параметра-значения, поэтому код, подобный этому, завершится ошибкой:

Foo := IfThen(Obj = nil, '<none>', Obj.Name);

Чтобы действительно сделать это правильно, нужна помощь от компилятора. В сообществе Delphi я чувствую общую неприязнь к синтаксису в стиле C, используя знак вопроса и двоеточие. Я видел предложения, которые будут использовать синтаксис, подобный этому:

Foo := if Obj = nil then
         '<none>'
       else
         Obj.Name;

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

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

Foo := Iif(Obj = nil, '<none>', Obj.Name);

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

Вы спросили, будет ли когда-нибудь в Delphi такая функция. Я не причастен к совещаниям по планированию Embarcadero, и мне пришлось отослать свой хрустальный шар для ремонта, поэтому я не могу сказать наверняка, но я предсказываю, что если бы у была бы такая функция, это придет в форме функции Iif Delphi Prism. Эта идея появляется ближе к концу обсуждения в Quality Central , и выдвигается возражение, что, как новое зарезервированное слово, оно нарушит обратную совместимость с кодом других людей, который уже определяет функцию с таким же название. Это не допустимый объект, потому что это не должно быть зарезервированным словом. Это может быть идентификатор, и точно так же, как Writeln и Exit, он может быть переопределен в других единицах, даже если один из системных единиц обрабатывается специально.

5 голосов
/ 09 марта 2011

Хорошо. Код WTF дня:)

Как получить то, что в основном действует как троичная / условная функция.

program Project107;
{$APPTYPE CONSOLE}

uses SysUtils;

type
  TLazyIfThen<T:record>=record
    class function IfThen(aCondition:Boolean;aIfTrue, aIfFalse:TFunc<T>):T; static;
  end;

  class function TLazyIfThen<T>.IfThen(aCondition:Boolean;aIfTrue, aIfFalse:TFunc<T>):T;
  begin
    if aCondition then
      Result := aIfTrue
    else
      Result := aIfFalse
  end;

begin
  WriteLn(
    TLazyIfThen<Integer>.IfThen(
      True,
      function:Integer begin result := 0 end,
      function:Integer begin result := 1 end
    )
  );
  ReadLn;
end.

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

5 голосов
/ 21 января 2010

Существует несколько доступных ручек простого типа для перегруженной функции IFTHEN.

StrUtils.IfThen (String)

Math.IfThen (Integer)

Math.IfThen (Int64)

Math.IfThen (Double) (также работает для TDateTime)

Эта модель падает, как показано в примере, который прокомментировал Андреас, но для простых типов это более чем разумно. If следует соглашению методов Delphi / Pascal, а не уступает C-способу использования как можно меньшего количества символов.

Лично я бы предпочел не видеть условный оператор (т. Е. ?:), введенный в Delphi, поскольку я предпочитаю удобочитаемость Delphi / Pascal по сравнению с C и его производными языками. Я предпочел бы видеть более инновационные решения типа Delphi для чего-то подобного, чем реализовывать больше C-isms.

5 голосов
/ 21 января 2010

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

Поднято в июне 2004 года, и, по-видимому, от Borland / CodeGear / Embarcadero ответа нет.

4 голосов
/ 21 января 2010

В Delphi нет условного оператора, и я серьезно сомневаюсь, будет ли он когда-либо, но вы никогда не узнаете.Вы всегда можете отправить запрос в Embarcadero.

Альтернативой является определение функции Iff:

function Iff(const ACondition: Boolean; const ATrueValue, AFalseValue: XXX): XXX;
begin
  if ACondition then
    Result := ATrueValue
  else
    Result := AFalseValue;
end;

Где XXX - это тип desirec.

Использовать как:

Result := Result + Iff(combo.text='', 'null', quotedStr(combo.text));

Существует несколько причин, по которым не следует реализовывать условный оператор.Одним из них является удобочитаемость.Паскаль (а также Delphi) больше сосредоточены на удобочитаемости, чем языки Синтаксиса C, которые в большей степени сосредоточены на символьной мощности (как можно больше информации на символ).Условный оператор мощный, но (по некоторым данным) не читаемый.Но если вы посмотрите на (страшно) с утверждением в Delphi ... (не нужно больше говорить).Другая причина в том, что условный оператор не требуется.Что является правдой.Но есть еще и необязательное, которое все еще реализуется.

В конце концов, это просто вопрос вкуса.

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

[overdesignmode]

// Please don't take this that serious.
type
  TFunc = function(): XXX;
function Iff(const ACondition: Boolean; const ATrueFunc, AFalseFunc: TFunc): XXX;
begin
  if ACondition then
    ATrueFunc
  else
    AFalseFunc;
end;

[/ overdesignmode]

3 голосов
/ 31 января 2010

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

http://www.digitalmars.com/d/2.0/lazy-evaluation.html

Приветствия

1 голос
/ 19 ноября 2013

Другой вариант - использовать дженерики:

Cond<T> = class
    public class function IIF(Cond: boolean; IfVal: T; ElseVal: T): T;
  end;

implementation

class function Cond<T>.IIF(Cond: boolean; IfVal, ElseVal: T): T;
begin
  if Cond then
    Result := IfVal
  else
    Result := ElseVal;
end;

Это вполне читабельно:

var MyInt: Integer;
begin
  MyInt:= Cond<Integer>.IIF(someCondition, 0, 42);

примечание: как указал Алан Брайант (в 21.06.2004, 7:26:21) в QR 8451 , это всегда оценивает все 3 аргумента - так что имейте в виду, что это не истинный троичный оператор.

1 голос
/ 21 января 2010

На самом деле для строк вы можете использовать: StrUtils.IfThen функция:

function IfThen(AValue: Boolean;
        const ATrue: string;
        AFalse: string = ): string; overload;

Посмотрите в справке Delphi вики: http://docwiki.embarcadero.com/VCL/en/StrUtils.IfThen

Он делает именно то, что вам нужно.

0 голосов
/ 03 июня 2019

WTF код дня №. 2:

program TernaryOpTest;

uses
  System.SysUtils, Vcl.Dialogs;

type
  TGetValue = reference to function(): Double;

function TernaryOp(condition: Boolean; trueFunc, falseFunc: TGetValue): Double;
begin
  if condition then begin
    if Assigned(trueFunc) then Result := trueFunc() else raise EArgumentNilException.Create('trueFunc not defined.');
  end
  else begin
    if Assigned(falseFunc) then Result := falseFunc() else raise EArgumentNilException.Create('falseFunc not defined.');
  end;
end;

procedure TernaryTest(x: Double);
var
  v: Double;
begin
  v := TernaryOp(x <> 0, function(): Double begin Result := 1/x; ShowMessage('True case'); end, function(): Double begin Result := 0; ShowMessage('False case'); end);
  ShowMessage(FloatToStr(v));
end;

begin
  ShowMessage('Testing true case');
  TernaryTest(10);
  ShowMessage('Testing false case');
  TernaryTest(0);
  ShowMessage('Testing exception');
  TernaryOp(False, nil, nil);
end.

Одна из возможных модификаций для типа данных Variant:

type
  TGetValue = reference to function(): Variant;

function TernaryOp(condition: Boolean; trueFunc, falseFunc: TGetValue): Variant;
begin
  Result := Unassigned;
  if condition then begin
    if Assigned(trueFunc) then Result := trueFunc();
  end
  else begin
    if Assigned(falseFunc) then Result := falseFunc();
  end;
end;
0 голосов
/ 07 марта 2011

В библиотеке кодов Jedi (JCL) реализован троичный оператор с набором функций с именем Iff (). Смотрите документацию здесь:

http://wiki.delphi -jedi.org / вики / JCL_Help: Ифф @ Boolean @ Boolean @ Boolean

Чтобы скачать JCL, посетите этот сайт:

http://sourceforge.net/projects/jcl/

...