Подтвердить что ты не робот

Есть ли, или будет когда-нибудь, условный оператор в Delphi?

Я слишком долго держал руки у Дельфи, наверное; За последние пару лет я много занимался 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 (generics) 2009 года было сделано несколько языков, поэтому почему бы не добавить эту функцию?

4b9b3361

Ответ 1

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

Ответ 2

Здесь есть отчет о контроле качества (8451), который имеет разумное обсуждение.

Поднято в июне 2004 года, и, похоже, от Borland/CodeGear/Embarcadero не было ответа.

Ответ 3

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

StrUtils.IfThen (String)

Math.IfThen (Integer)

Math.IfThen (Int64)

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

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

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

Ответ 4

Ok. Код 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

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

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

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

Где XXX - тип желания.

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

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]

Ответ 6

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

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

Приветствия

Ответ 7

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

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

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

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

Ответ 8

Другой вариант - использовать generics:

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);

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

Ответ 9

Еще лучше - перегруженный IIF (inline if), который поддерживает несколько типов данных и результатов.

Ответ 11

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 TernatyTest(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');
  TernatyTest(10);
  ShowMessage('Testing false case');
  TernatyTest(0);
  ShowMessage('Testing exception');
  TernaryOp(False, nil, nil);
end.