¿Hay, o habrá alguna vez, un operador condicional en Delphi?
delphi-2009 language-features (10)
Mantuve mis manos lejos de Delphi durante demasiado tiempo, supongo; me ocupé mucho de Java y PHP en los últimos años. Ahora, cuando volví a hacer un pequeño trabajo en Delphi, me di cuenta de que realmente extrañaba el operador condicional que es compatible tanto con Java como con PHP.
¿En cuántos lugares encontrarías líneas como estas en tus programas 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;
donde un simple
result := result + (combo.text='''')?''null'':quotedStr(combo.text);
bastaría. Lo que me gusta de esto es que no solo acorta el código, de esta manera también evito declarar alguna variable auxiliar s:string
.
¿Por qué los operadores condicionales no son parte de Delphi y - alguna vez van a ser compatibles? Noté que había bastantes extensiones de lenguaje hechas para la versión 2009 de Delphi (genéricos), ¿por qué no agregar esta característica?
De acuerdo. Código WTF del día :)
Cómo obtener algo que en su mayoría actúa como una función ternaria / condicional.
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.
Sí, es más o menos inútil, pero muestra que se puede hacer.
En realidad, para cadenas de caracteres puede usar la función: StrUtils.IfThen :
function IfThen(AValue: Boolean;
const ATrue: string;
AFalse: string = ): string; overload;
Mire en la wiki de ayuda de Delphi: http://docwiki.embarcadero.com/VCL/en/StrUtils.IfThen
Hace exactamente lo que necesita.
Hay un informe de control de calidad sobre esto ( 8451 ) que tiene una discusión razonable.
Criado en junio de 2004, y no parece haber ninguna respuesta de Borland / CodeGear / Embarcadero.
Hay una cantidad de identificadores de tipo simple disponibles en la función IFTHEN sobrecargada.
StrUtils.IfThen
( String
)
Math.IfThen
( Integer
)
Math.IfThen
( Int64
)
Math.IfThen
( Double
) (funciona para TDateTime
también)
Este modelo se cae como se muestra en el ejemplo que Andreas comentó, pero para los tipos simples esto es más que razonable. Si sigue la convención de métodos Delphi / Pascal en lugar de sucumbir a la forma C de usar la menor cantidad de caracteres posible.
Personalmente, preferiría no ver un operador condicional (es decir,?:) Introducido en Delphi ya que prefiero la legibilidad de Delphi / Pascal sobre C y los idiomas derivados. Preferiría ver soluciones de tipo Delphi más innovadoras para algo como esto que implementar más C-ismos.
Jedi Code Library (JCL) ha implementado el operador operante ternario con un conjunto de funciones llamadas Iff (). Vea aquí para la documentación:
http://wiki.delphi-jedi.org/wiki/JCL_Help:Iff@Boolean@Boolean@Boolean
Para descargar JCL, puede visitar este sitio:
Mejor aún es un IIF sobrecargado (en línea si) que admite múltiples tipos de datos y resultados.
No hay un operador condicional en Delphi, y dudo seriamente si alguna vez habrá uno, pero nunca se sabe. Siempre puede emitir una solicitud en Embarcadero.
Una alternativa es definir la función Iff:
function Iff(const ACondition: Boolean; const ATrueValue, AFalseValue: XXX): XXX;
begin
if ACondition then
Result := ATrueValue
else
Result := AFalseValue;
end;
Donde XXX es el tipo desirec.
Usar como:
Result := Result + Iff(combo.text='''', ''null'', quotedStr(combo.text));
Hay varias razones por las cuales no implementar el operador condicional. Uno de estos es la legibilidad. Pascal (y también Delphi) está más centrado en la legibilidad que en los lenguajes de sintaxis de C, que están más centrados en el poder del personaje (tanta información por personaje como sea posible). El operador condicional es poderoso pero (según algunos) no legible. Pero si miras la (temida) declaración en Delphi ... (no hace falta decir más). Otra razón es que no se requiere el operador condicional. Cual es verdad. Pero no se requiere más que todavía se implemente.
Al final, es solo una cuestión de gusto.
Pero si solo quiere evaluar un argumento, siempre puede usar el seguimiento, que infringe tanto la legibilidad como el concepto de poder del personaje:
[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]
Otra opción es usar genéricos:
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;
Esto es bastante legible:
var MyInt: Integer;
begin
MyInt:= Cond<Integer>.IIF(someCondition, 0, 42);
Nota: como señaló Alan Bryant (al 21/6/2004 7:26:21 AM) en QR 8451 , esto siempre evaluará los 3 argumentos, así que tenga en cuenta que no es un verdadero operador ternario.
Preferiría que implementaran evaluación diferida y será más potente y se puede usar en diferentes escenarios. Ver detalle como enlace debajo
http://www.digitalmars.com/d/2.0/lazy-evaluation.html
Aclamaciones
Tal operador no es parte de la versión actual de Delphi porque no era parte de la versión anterior, y la demanda no era lo suficientemente grande como para justificar el costo de agregarla. (Encontrará que la explicación se aplica a muchas características que le gustaría tener en muchos productos).
Delphi proporciona un conjunto de funciones IfThen
en las unidades Math y StrUtils, pero tienen la desafortunada propiedad de evaluar ambos parámetros de valor, por lo que un código como este fracasará:
Foo := IfThen(Obj = nil, ''<none>'', Obj.Name);
Para hacerlo bien, es necesario que haya una ayuda del compilador. Dentro de la comunidad Delphi, siento una aversión general hacia la sintaxis estilo C usando un signo de interrogación y dos puntos. He visto propuestas que utilizarían una sintaxis como esta:
Foo := if Obj = nil then
''<none>''
else
Obj.Name;
Parte de lo que hace que los operadores condicionales sean tan atractivos es que te permiten escribir un código conciso, pero el estilo de Delphi de escribir todo hace que lo anterior sea poco atractivo, incluso si lo pones todo en una línea.
Realmente no necesita estar en la forma de un operador . Delphi Prism proporciona una función de compilación mágica Iif
que solo evalúa uno de sus dos parámetros de valor:
Foo := Iif(Obj = nil, ''<none>'', Obj.Name);
Usted preguntó por qué una característica como esta no se habría agregado junto con todas las otras características de idioma agregadas en Delphi 2009. Creo que esa es su razón. Hubo muchos otros cambios de lenguaje que ya requerían un manejo delicado; los desarrolladores no tuvieron que cargar con más. Las características no son gratis.
Usted preguntó si Delphi tendrá alguna vez esa característica. No estoy al tanto de las reuniones de planificación de Embarcadero, y tuve que enviar mi bola de cristal para reparaciones, así que no puedo decirlo con certeza, pero predigo que si alguna vez tuviera esa característica, vendría en la forma de la función Iif
de Delphi Prism. Esa idea aparece cerca del final de la discusión en Quality Central , y se hace una objeción de que, como una nueva palabra reservada, rompería la compatibilidad con el código de otras personas que ya define una función con el mismo nombre. Sin embargo, ese no es un objeto válido, porque no necesitaría ser una palabra reservada. Podría ser un identificador, y al igual que Writeln
y Exit
, puede ser elegible para ser redefinido en otras unidades a pesar de que el de la unidad del sistema se trata de manera especial.