I kept my hands off Delphi for too long, I guess; busied myself with Java and PHP a lot over the last couple of years. Now, when I got back to doing a little Delphi job, I realised I really miss the conditional operator which is supported by both Java and PHP.
On how many places would you find lines like these in your Delphi programs?
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;
where a simple
result := result + (combo.text='')?'null':quotedStr(combo.text);
would suffice. What I like about this is that it not only shortens the code, this way I also avoid declaring some helper s:string
variable.
Why are conditional operators not part of Delphi and - are they ever going to be supported? I noticed there were quite a few language extensions made for the 2009 version of Delphi (generics), so why not add this feature?
Such an operator isn't part of the current Delphi version because it wasn't part of the previous version, and demand wasn't great enough to justify the cost of adding it. (You'll find that explanation applies to lots of features you wish you had in lots of products.)
Delphi provides a set of IfThen
functions in the Math and StrUtils units, but they have the unfortunate property of evaluating both their value parameters, so code like this will fail:
Foo := IfThen(Obj = nil, '<none>', Obj.Name);
To really do it right, there needs to be help from the compiler. Within the Delphi community, I sense a general dislike of the C-style syntax using a question mark and a colon. I've seen proposals that would use syntax like this:
Foo := if Obj = nil then
'<none>'
else
Obj.Name;
Part of what makes conditional operators so attractive is that they let you write concise code, but Delphi's style of writing everything out makes the above unappealing, even if put all on one line.
It doesn't really need to be in the form of an operator. Delphi Prism provides a compiler-magic function Iif
that only evaluates one of its two value parameters:
Foo := Iif(Obj = nil, '<none>', Obj.Name);
You asked why a feature like this wouldn't have been added along with all the other language features added in Delphi 2009. I think that's your reason. There were plenty of other language changes going on that already required delicate handling; the developers didn't need to be burdened with even more. Features aren't free.
You asked whether Delphi will ever have such a feature. I'm not privy to Embarcadero's planning meetings, and I had to send my crystal ball away for repairs, so I can't say for certain, but I predict that if it ever would have such a feature, it would come in the form of Delphi Prism's Iif
function. That idea shows up near the end of the discussion in Quality Central, and an objection is made that, as a new reserved word, it would break backward compatibility with other people's code that already defines a function with the same name. That's not a valid object, though, because it wouldn't need to be a reserved word. It could be an identifier, and just like Writeln
and Exit
, it can be eligible to be redefined in other units even though the one from the System unit is treated specially.
There's a QC report on this (8451) which has a reasonable discussion.
Raised June 2004, and there doesn't appear to be any response from Borland/CodeGear/Embarcadero.
Ok. WTF code of the day :)
How to get something that mostly acts like a ternary/conditional function.
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.
Yeah, it's more or less useless, but it shows that it can be done.
There are a number of available simple type handles on the overloaded IFTHEN function.
StrUtils.IfThen
(String
)
Math.IfThen
(Integer
)
Math.IfThen
(Int64
)
Math.IfThen
(Double
) (works for TDateTime
as well)
This model falls down as shown in the example that Andreas commented on, but for simple types this is more than reasonable. If follows the Delphi/Pascal convention of methods rather than succumbing to the C way of using the least amount of characters as possible.
Personally I would rather not see a conditional operator (i.e. ?:
) introduced in Delphi as I prefer the readability of Delphi/Pascal over C and it derivative languages. I would prefer to see more innovative Delphi type solutions to something like this than to implement more C-isms.
There is no conditional operator in Delphi, and I seriously doubt if there will ever be one but you may never know. You can always issue a request at Embarcadero.
An alternative is to define the Iff function:
function Iff(const ACondition: Boolean; const ATrueValue, AFalseValue: XXX): XXX;
begin
if ACondition then
Result := ATrueValue
else
Result := AFalseValue;
end;
Where XXX is the desirec type.
Use as:
Result := Result + Iff(combo.text='', 'null', quotedStr(combo.text));
There are several reasons why not to implement the conditional operator. One of these is readability. Pascal (and also Delphi) is more centered on Readability than the C Syntax languages which are more centered on character power (as much information per character as possible). The conditional operator is powerful but (according to some) not readable. But if you look at the (dreaded) with statement in Delphi... (no need to say more). Another reason is that the conditional operator is not required. Which is true. But there is more not required that is still implemented.
In the end it's just a matter of taste.
But if you want just one argument to be evaluated, you can always use the folowing, which violates both the readability as the character power concept:
[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]
I would prefer them to to implement lazy evaluation and it will be more powerful and can be used in different scenario. See detail as below link
http://www.digitalmars.com/d/2.0/lazy-evaluation.html
Cheers
Actually for strings you can use the: StrUtils.IfThen function:
function IfThen(AValue: Boolean;
const ATrue: string;
AFalse: string = ): string; overload;
Look in the delphi help wiki: http://docwiki.embarcadero.com/VCL/en/StrUtils.IfThen
It does exactly what you need.
Another option is to use 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;
This is quite readable:
var MyInt: Integer;
begin
MyInt:= Cond<Integer>.IIF(someCondition, 0, 42);
note: as pointed out by Alan Bryant (at 6/21/2004 7:26:21 AM) in QR 8451, this will always evaluate all 3 arguments - so be aware that it's not a true ternary operator.
Better yet is an overloaded IIF (inline if) that supports multiple datatypes and results.
Jedi Code Library ( JCL ) has implemented the ternary operaror with a set of functions named Iff(). See here for documentation:
http://wiki.delphi-jedi.org/wiki/JCL_Help:Iff@Boolean@Boolean@Boolean
To download JCL you can visit this site:
WTF code of the day Nr. 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.
One possible modification for Variant data type is:
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;
来源:https://stackoverflow.com/questions/2108609/is-there-or-is-there-ever-going-to-be-a-conditional-operator-in-delphi