2009-02-07 11 views
7

¿Hay problemas de comprensión/mantenibilidad que resultan de código como¿Es este un uso razonable del operador ternario?

inVar1 == 0 ? NULL : v.push_back(inVar1); 
inVar2 == 0 ? NULL : v.push_back(inVar2); 

y así sucesivamente.

La idea posiblemente confusa es usar el operador ternario para el flujo del programa en lugar de la asignación de variables, que es la explicación habitual.

No he visto normas de codificación en el trabajo que aborden este uso, así que mientras me siento cómodo haciendo esto me gustaría saber si hay una buena razón para no hacerlo.

+1

y tenga en cuenta que su cosa es incluso incorrecta en C++. si un operando es nulo, entonces el otro tiene que ser también, o tiene que tirar: inVar1 == 0? (void) NULL: v.push_back (inVar1); simplemente use un simple si :) –

+0

Tengo que estar en desacuerdo con "incorrecto" - VisualStudio 2003 y 2005 lo permiten. ¿Quizás podamos debatir qué significa "incorrecto" ...? – user63572

+0

incorrecto significa cuando su código no es válido C++, por supuesto. una rama tiene tipo void y otra tiene tipo int, long o algo así. eso no es válido vacío y mordisco int. tal vez vC++ tiene una extensión que permite esto, no sé. –

Respuesta

35

Creo que es confuso y mucho más difícil de leer que simplemente escribir;

if (inVar != 0) 
    v.push_back(inVar); 

Tuve que escanear tu ejemplo varias veces para averiguar cuál sería el resultado con certeza. Incluso preferiría una sentencia if() {} de línea única que tu ejemplo, y odio las sentencias if de una línea :)

+0

Creo que ed-malabar debería juzgar la legibilidad determinando cuánto tiempo estaba _spent_ tratando de descubrir el código. Semánticamente, es muy simple. No debería tomarme buenos 30 segundos para entenderlo completamente. – Calyth

+1

Estoy de acuerdo, parece que el consenso popular es que se pasa más tiempo analizando el código que desplazándose. – user63572

10

Creo que esto debe evitarse. Podría usar una instrucción if de 1 línea en su lugar.

if(inVar1 != 0) v.push_back(inVar1); 
+0

Esto es desagradable: nunca hay una buena razón para no marcar bloques con bracecs circundantes. –

+3

@mP: Hay: pereza y, a veces, incluso legibilidad; A menudo hago cosas como 'if (! Buffer) return NULL;' para verificar los valores de retorno/condiciones de error, y me resulta mucho más fácil leer si * not * rodeado de llaves, independientemente de lo que digan algunas convenciones de codificación. – Christoph

+5

@mP: No tiene que seguir ciegamente las convenciones de codificación sin * pensar * acerca de por qué existen. No siempre necesitas llaves alrededor de cada bloque si. –

25

El operador ternario debe devolver un valor.

IMO, no debe mutar el estado, y se debe usar el valor de retorno.

En el otro caso, use las sentencias if. Si las declaraciones están destinadas a ejecutar bloques de código.

+0

Pero el valor de retorno se está utilizando. – abelito

1

Creo que sería mejor si se hace una estructura adecuada. Incluso prefiero tener llaves siempre con mis estructuras if, en caso de que tenga que agregar líneas más adelante a la ejecución condicional.

if (inVar != 0) { 
    v.push_back(inVar); 
} 
6

Los compiladores en estos días harán un tan rápido como un operador ternario.

Su objetivo debe ser qué tan fácil es de leer para otro desarrollador de software.

voto por

if (inVar != 0) 
{ 
    v.push_back(inVar); 
} 

por qué los soportes ... porque un día es posible que desee poner algo más ahí y los soportes son pre-hecho por ti. La mayoría de los editores estos días los pondrán de todos modos.

+1

Excepto en casos raros, odio al operador ternario. Es difícil de leer, difícil de escanear visualmente para los campos discretos involucrados, y fácil de perder dentro de un bloque de código más grande. – Joe

+1

Estoy de acuerdo, lo evito como la peste. –

+1

Siempre he pensado que el razonamiento es extraño (poner los corchetes de inmediato) - ¿Es realmente más difícil incluirlos más tarde cuando decides que los necesitas? – Eclipse

2

Si bien, en la práctica, estoy de acuerdo con los sentimientos de aquellos que desalientan este tipo de escritura (al leer, tienes que hacer un trabajo extra para escanear la expresión por sus efectos secundarios), me gustaría ofrecer

!inVar1 ?: v.push_back(inVar1); 
!inVar2 ?: v.push_back(inVar2); 

... si vas por oscuro, eso es. GCC permite x ?: y en lugar de x ? x : y. :-)

+0

¡Agradable! Mi intención no era ofuscar el código, simplemente para evitar una expansión vertical innecesaria. VS2005 no le gusta?: Though. Dang. – user63572

+0

No dije que fuera una buena idea, simplemente lo ofrecí como una posibilidad. – ephemient

6

Su uso del operador ternario no le gana nada y perjudica la legibilidad de los códigos.

Como el operador ternario devuelve un valor que no está utilizando, es un código impar. El uso de un if es mucho más claro en un caso como el suyo.

11

El ternario es algo bueno, y generalmente promuevo su uso.

Lo que está haciendo aquí, sin embargo, empaña su credibilidad. Es más corto, sí, pero es innecesariamente complicado.

5

Como litb mencionó en los comentarios, este isn't valid C++. GCC, por ejemplo, emitirá un error en el código:

error: `(&v)->std::vector<_Tp, _Alloc>::push_back [with _Tp = int, _Alloc = 
std::allocator<int>](((const int&)((const int*)(&inVar1))))' has type `void' 
and is not a throw-expression 

Sin embargo, esto se puede evitar mediante fundición:

inVar1 == 0 ? (void)0 : v.push_back(inVar1); 
inVar2 == 0 ? (void)0 : v.push_back(inVar2); 

Pero a qué costo? ¿Y para qué?

No es como usar el operador ternario aquí es más concisa de una sentencia if en esta situación:

inVar1 == 0 ? NULL : v.push_back(inVar1); 
if(inVar1 != 0) v.push_back(inVar1); 
2

utilizo operador ternario cuando tengo que llamar a alguna función con argumentos condicionales - en este caso, es mejor que if.

Compare:

printf("%s while executing SQL: %s", 
     is_sql_err() ? "Error" : "Warning", sql_msg()); 

con

if (is_sql_err()) 
    printf("Error while executing SQL: %s", sql_msg()); 
else 
    printf("Warning while executing SQL: %s", sql_msg()); 

Me parece que el primero es más atractiva. Y cumple con el principio DRY, a diferencia de este último: no necesita escribir dos líneas casi idénticas.

+0

La versión de operador condicional ternario también enfatiza la parte principal del código (impresión) en lugar de la parte menor del código, ya sea una advertencia o un error. –

0

Si tiene varias invocaciones de método en uno o ambos argumentos del tenario, entonces es incorrecto. Todas las líneas de código independientemente de qué enunciado deben ser breves y simples, idealmente no compuestas.

0

Una declaración if adecuada es más legible, como otros han mencionado. Además, cuando revise su código con un depurador, no podrá ver fácilmente qué rama de un si se toma cuando todo está en una línea o si está utilizando una expresión ternaria:

if (cond) doIt(); 

cond ? noop() : doIt(); 

Mientras que la siguiente es mucho más agradable al paso a través (si tiene las llaves o no):

if (cond) { 
    doIt(); 
} 
1

Creo que a veces la ternaria son un mal necesario en las listas inicializador para los constructores. Los uso principalmente para constructores en los que quiero asignar memoria y establecer algún puntero para señalarlo antes que el cuerpo del constructor.

un ejemplo, supongamos que tiene una clase de almacenamiento entero que quería tener tome un vector como una entrada, pero la representación interna es una matriz:

class foo 
{ 
public: 
    foo(std::vector<int> input); 
private: 
    int* array; 
    unsigned int size; 
}; 

foo:foo(std::vector<int> input):size(input.size()), array((input.size()==0)? 
     NULL : new int[input.size]) 
{ 
    //code to copy elements and do other start up goes here 
} 

Ésta es la forma en que uso el operador ternario. No creo que sea tan confuso como algunas personas lo hacen, pero creo que uno debe limitar la cantidad que lo usan.

1

La mayoría de los ternarios torturados (¿cómo es eso de la aliteración?) Veo que son simplemente intentos de poner la lógica que realmente pertenece en una declaración if en un lugar donde una sentencia if no pertenece o no puede ir.

Por ejemplo:

if (inVar1 != 0) 
    v.push_back(inVar1); 
if (inVar2 != 0) 
    v.push_back(inVar2); 

obras suponiendo que v.push_back es nula, pero lo que si se trata de devolver un valor que hay que conseguir pasar a otra función? En ese caso, tendría que verse algo como esto:

SomeType st; 
if (inVar1 != 0) 
    st = v.push_back(inVar1); 
else if (inVar2 != 0) 
    st = v.push_back(inVar2); 
SomeFunc(st); 

Pero eso es más que digerir para una pieza tan simple de código. Mi solución: definir otra función.

SomeType GetST(V v, int inVar1, int inVar2){ 
    if (inVar1 != 0) 
     return v.push_back(inVar1); 
    if (inVar2 != 0) 
     return v.push_back(inVar2);   
} 

//elsewhere 
SomeFunc(GetST(V v, inVar1, inVar2)); 

En cualquier caso, la cuestión es la siguiente: si tiene algo de lógica que es demasiado torturado por un ternaria sino que estorbar encima de su código si se trata de poner en una sentencia if, lo puso en otro lugar!

0

Como se mencionó, no es más corta o más clara que una declaración de 1 línea si. Sin embargo, ya no es más, y no es tan difícil de asimilar. Si conoces al operador ternario, es bastante obvio lo que está sucediendo.

Después de todo, yo no creo que nadie tendría problemas si se estuviese asignado a una variable (incluso si fue mutando estado también):

var2 = inVar1 == 0 ? NULL : v.push_back(inVar1); 

El hecho de que el operador ternario siempre devuelve un valor - IMO - es irrelevante. Ciertamente, no es necesario que use todos los valores devueltos ... después de todo, una asignación devuelve un valor.

Dicho esto, lo reemplazaría con una declaración if si lo encontré con una rama NULL.

Pero, si se sustituye una línea de 3 if:

if (inVar == 0) { 
    v.doThingOne(1); 
} else { 
    v.doThingTwo(2); 
} 

con:

invar1 == 0 ? v.doThingOne(1) : v.doThingTwo(2); 

I podría dejarlo ... dependiendo de mi estado de ánimo. ;)

1
inVar1 != 0 || v.push_back(inVar1); 
inVar2 != 0 || v.push_back(inVar2); 

patrón común encontrado en idiomas como Perl.

+1

Esta es la revisión más confusa inicial de mi código de muestra en este hilo. Pero después de la WTF inicial, analiza. Y me hace imaginar que los desarrolladores de Perl tienen monitores muy pequeños. – user63572

+0

No es un patrón común en idiomas como C, sin embargo. –

Cuestiones relacionadas