¿Hay alguna diferencia entre SÍ / NO, VERDADERO / FALSO y verdadero / falso en el objetivo-c?

154

Pregunta simple realmente; ¿Hay alguna diferencia entre estos valores (y hay una diferencia entre BOOL y bool)? Un compañero de trabajo mencionó que evalúan diferentes cosas en Objective-C, pero cuando miré los typedefs en sus respectivos archivos .h, YES / TRUE / true se definieron como 1NO y FALSE / false se definieron como 0. Hay realmente alguna diferencia?

Kevlar
fuente
55
Desde un punto de vista práctico, no hay diferencia. Probablemente puedas hacer varios trucos para demostrar una diferencia, pero generalmente te estarías desviando hacia un territorio de "comportamiento indefinido".
Hot Licks

Respuestas:

84

No hay diferencia práctica siempre que use BOOLvariables como booleanos. C procesa expresiones booleanas en función de si evalúan a 0 o no a 0. Entonces:

if(someVar ) { ... }
if(!someVar) { ... }

significa lo mismo que

if(someVar!=0) { ... }
if(someVar==0) { ... }

Es por eso que puede evaluar cualquier tipo o expresión primitiva como una prueba booleana (incluidos, por ejemplo, punteros). Tenga en cuenta que debe hacer lo primero, no lo segundo.

Tenga en cuenta que no es una diferencia si asigna valores obtusos a una llamada BOOLvariable y prueba para valores específicos, por lo que siempre utilizarlos como booleanos y sólo asignarlos a partir de sus #definevalores.

Es importante destacar que nunca pruebe booleanos utilizando una comparación de caracteres: no solo es arriesgado, ya que someVarpodría asignarse un valor distinto de cero que no sea SÍ, sino que, en mi opinión, lo más importante es que no expresa la intención correctamente:

if(someVar==YES) { ... } // don't do this!
if(someVar==NO ) { ... } // don't do this either!

En otras palabras, use construcciones como están destinadas y documentadas para ser utilizadas y se ahorrará un mundo de dolor en C.

Lawrence Dol
fuente
100

Creo que es una diferencia entre booly BOOL, echa un vistazo a la página para una explicación de por qué:
http://iosdevelopertips.com/objective-c/of-bool-and-yes.html

Como BOOLes un tipo unsigned charmás que primitivo, las variables de tipo BOOLpueden contener valores distintos de YESy NO.

Considera este código:

BOOL b = 42;

if (b) {
    printf("b is not NO!\n");
}

if (b != YES) {
    printf("b is not YES!\n");
}

El resultado es:

b no es NO!
b no es SI!

Para la mayoría de las personas, esta es una preocupación innecesaria, pero si realmente quieres un booleano, es mejor usar a bool. Debo agregar: el SDK de iOS generalmente usa BOOLen sus definiciones de interfaz, por lo que es un argumento para seguir BOOL.

Dan J
fuente
55
Pero tenga en cuenta que la implementación original de C no tenía bool, y por lo tanto, ha sido la tradición usar un into charcomo un booleano, a veces con un #definir para ocultar la diferencia y otras no. De hecho, no estoy seguro si incluso los estándares actuales requieren boolser implementados de una manera que evite examinar su estructura interna.
Hot Licks el
1
Aunque, el primero printfdice mentiras. El valor de bno es YES, es "no cero", que es lo que prueba la condición. Entonces deberías tener printf("b is not zero"), que no es necesariamente lo mismo que YES. En este caso, bes "no cero" y "no SÍ".
Lawrence Dol
Gracias Lawrence, he hecho una actualización en ese sentido.
Dan J
De hecho, no obtuve la segunda salida en Xcode 8.2. Donde fallo?
Igor Kislyuk
1
@HotLicks no hay diferencia inherente entre 0, no cero y falso y verdadero. Mientras el valor esté destinado a ser un booleano lógico, siempre tendrá esta interfaz para preservar la compatibilidad binaria. Los problemas comienzan cuando usa booleanos que parecen booleanos, por ejemplo, la función de entrada de aplicación de biblioteca estándar c, main devuelve 0 en caso de éxito, muchos terminan pensando en este 0 como un booleano, cuando en realidad es una enumeración definida por la aplicación o definida por el usuario valor, que a menudo se espera que sea distinto de cero en una terminación anormal.
Dmitry
52

Hice una prueba exhaustiva sobre esto. Mis resultados deberían hablar por sí mismos:

//These will all print "1"
NSLog(@"%d", true == true);
NSLog(@"%d", TRUE == true);
NSLog(@"%d", YES  == true);
NSLog(@"%d", true == TRUE);
NSLog(@"%d", TRUE == TRUE);
NSLog(@"%d", YES  == TRUE);
NSLog(@"%d", true == YES);
NSLog(@"%d", TRUE == YES);
NSLog(@"%d", YES  == YES);

NSLog(@"%d", false == false);
NSLog(@"%d", FALSE == false);
NSLog(@"%d", NO    == false);
NSLog(@"%d", false == FALSE);
NSLog(@"%d", FALSE == FALSE);
NSLog(@"%d", NO    == FALSE);
NSLog(@"%d", false == NO);
NSLog(@"%d", FALSE == NO);
NSLog(@"%d", NO    == NO);


//These will all print "0"
NSLog(@"%d", false == true);
NSLog(@"%d", FALSE == true);
NSLog(@"%d", NO    == true);
NSLog(@"%d", false == TRUE);
NSLog(@"%d", FALSE == TRUE);
NSLog(@"%d", NO    == TRUE);
NSLog(@"%d", false == YES);
NSLog(@"%d", FALSE == YES);
NSLog(@"%d", NO    == YES);

NSLog(@"%d", true == false);
NSLog(@"%d", TRUE == false);
NSLog(@"%d", YES  == false);
NSLog(@"%d", true == FALSE);
NSLog(@"%d", TRUE == FALSE);
NSLog(@"%d", YES  == FALSE);
NSLog(@"%d", true == NO);
NSLog(@"%d", TRUE == NO);
NSLog(@"%d", YES  == NO);

El resultado es:

2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.072 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.076 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.082 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.091 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.092 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.097 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.098 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.101 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0
Supuhstar
fuente
3
[[NSObject] alloc] init] no es igual a TRUE o YES. Por lo tanto, la prueba de inicialización de objetos con if ([[NSObject] alloc] init] == ​​TRUE) fallará. Nunca me he sentido cómodo con un lenguaje que defina un valor "verdadero" singular cuando de hecho cualquier valor distinto de cero servirá.
DrFloyd5
3
@SamuelRenkert Nunca me he sentido cómodo con un lenguaje que tome un valor no booleano en un ifo un while. Como ... while("guitar gently weeps")no debería funcionar ...
Supuhstar
@SamuelRenkert también la puerta trasera de Linux que se encontró en 2003:if (user_id = ROOT_UID)
Supuhstar
14

Es posible que desee leer las respuestas a esta pregunta . En resumen, en Objective-C (de la definición en objc.h):

typedef signed char        BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#define OBJC_BOOL_DEFINED


#define YES             (BOOL)1
#define NO              (BOOL)0
Barry Wark
fuente
11

La principal diferencia (¡peligrosa!) Entre truey YESestá en la serialización JSON.

Por ejemplo, tenemos una solicitud de servidor de tipo JSON y necesitamos enviar verdadero / falso en sentido json:

NSDictionary *r1 = @{@"bool" : @(true)};
NSDictionary *r2 = @{@"bool" : @(YES)};
NSDictionary *r3 = @{@"bool" : @((BOOL)true)};

Luego lo convertimos a una cadena JSON antes de enviarlo como

NSData *data = [NSJSONSerialization  dataWithJSONObject:requestParams options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

El resultado es

jsonString1 // {"bool":1}
jsonString2 // {"bool":true}
jsonString3 // {"bool":true}

Debido a la lógica de la API jsonString1podría provocar un error.

Así que ten cuidado con los booleanos en Objective-C.

En resumen, solo los @YESvalores exactos y convertidos @((BOOL)expression)son de __NSCFBooleantipo y se convierten truecon serialización JSON. Cualquier otra expresión como @(expression1 && expression2)(even @(YES && YES)) es de __NSCFNumber (int)tipo y se convierte 1en JSON.

PD: simplemente puede usar un valor booleano de cadena

@{@"bool" : @"true"}; // in JSON {"bool":true}
malex
fuente
1

Hay un error sutil que nadie ha mencionado aquí, que pensé que incluiría ... más un error lógico que cualquier otra cosa:

int i = 2;
if(i);        //true
if(i==YES);   // false
if((!!i)==YES); //true

así que el problema aquí es solo eso (YES==1)y en C la comparación no es booleana, sino basada en el valor.

porque YESes solo un #define(en lugar de algo intrínseco al lenguaje), tiene que tener algún valor y 1tiene más sentido.

Grady Player
fuente
Esta es esencialmente la misma respuesta que la de DanJ, ​​de más de 2 años antes, con menos detalles.
Lawrence Dol
@LawrenceDol No lo sé, menciona que SÍ solo está #definido para ser 1 y no intrínseco al idioma, como si estuviera en un idioma de nivel superior ... alguien podría obtener valor de eso ... pero bueno trolling, contigo.
Grady Player
0

Creo que agregan SÍ / NO para explicarse más en muchos casos. Por ejemplo:

[button setHidden:YES];

suena mejor que

[button setHidden:TRUE];
Marco
fuente
2
Estoy en desacuerdo; los dos me leen lo mismo. Sin embargo, en una interfaz de usuario para un laico, creo que Sí / No se ve mejor.
Lawrence Dol
16
No estoy de acuerdo también. En todo caso, se lee mal debido a que no se apega a los estándares no escritos que se han utilizado durante años en otros idiomas. IE es un excelente ejemplo de lo que sucede cuando no cumple con una gran cantidad de estándares.
FreeAsInBeer
1
Mitad de voto negativo para 2 respuestas imprecisas y mitad de
voto negativo
-2

Primero examinemos qué es verdadero y falso y qué les da significado en primer lugar.

podemos construir una estructura llamada if a then b else c en cálculo lambda de la siguiente manera:

(\ifThenElse. <use if then else>)(\a. \b. \c. a b c)

En JavaScript, esto se ve así:

(function(ifThenElse) {
    // use ifThenElse
})(function(a) {
    return function(b) {
        return function(c) {
            return a(b)(c);
        };
    };
});

para que ifThenElse sea útil, necesitamos una función "true" que elija derecha o izquierda, y lo hace mientras ignora la otra opción, o una función "false" que elige la opción "true" no toma.

Podemos definir estas funciones de la siguiente manera:

(\true. <use true>)(\a. \b. a) and (\false. <use false>)(\a. \b. b)

en JavaScript se ve así:

(function(True) {
    // use True
})(function(a) {
     return function(b) {
         return a;
     }
});

(function(False) {
    // use True
})(function(a) {
     return function(b) {
         return b;
     }
});

ahora podemos hacer lo siguiente

(\true. \false. \ifThenElse. \doThis. \doThat. ifThenElse true doThis doThat)
(\a. \b. a)(\a. \b. b)(\a. \b. \c. a b c)(\a. ())(\a. ())

con doThis y doThat siendo (\ a. ()) porque el cálculo lambda no ofrece ningún servicio como impresión / matemática / cadenas, todo lo que podemos hacer es no hacer nada y decir que lo hicimos (y luego hacer trampa reemplazándolo con servicios en nuestro sistema que proporciona los efectos secundarios que queremos)

así que veamos esto en acción.

(function(True) {
    return (function(False) {
        return (function(ifThenElse) {
            return (function(doThis) {
                return (function(doThat) {
                    return ifThenElse(True)(doThis)(doThat);
                });
            });
        });
    })
})(function(a) {
     return function(b) {
         return a;
     }
})(function(a) {
     return function(b) {
         return b;
     }
})(function(a) {
    return function(b) {
        return function(c) {
            return a(b)(c);
        };
    };
})(function(a) { console.log("you chose LEFT!"); })
(function(a) {console.log("you chose RIGHT");})();

Ese es un entorno profundo que podría simplificarse si se nos permitiera usar matrices / mapas / argumentos / o más de una declaración para dividir en múltiples funciones, pero quiero mantenerlo tan puro como puedo limitarme a las funciones de exactamente un argumento solamente.

tenga en cuenta que el nombre Verdadero / Falso no tiene un significado inherente, podemos cambiarles el nombre fácilmente a sí / no, izquierda / derecha, derecha / izquierda, cero / uno, manzana / naranja. Tiene importancia porque cualquier elección que se haga, solo es causada por el tipo de elección que se hizo. Por lo tanto, si se imprime "IZQUIERDA", sabemos que el seleccionador solo puede ser verdadero y, en base a este conocimiento, podemos guiar nuestras decisiones adicionales.

Entonces para resumir

function ChooseRight(left) {
    return function _ChooseRight_inner(right) {
        return right;
    }
}
function ChooseLeft(left) {
    return function _ChooseLeft_inner(right) {
        return left;
    }
}

var env = {
    '0': ChooseLeft,
    '1': ChooseRight,
    'false': ChooseRight,
    'true': ChooseLeft,
    'no': ChooseRight
    'yes': ChooseLeft,
    'snd': ChooseRight,
    'fst': ChooseLeft
};
var _0 = env['0'];
var _1 = env['1'];
var _true = env['true'];
var _false = env['false'];
var yes = env['yes'];
var no = env['no'];

// encodes church zero or one to boolean
function lambda_encodeBoolean(self) {
    return self(false)(true);
}
// decodes a Boolean to church zero or one
function lambda_decodeBoolean(self) {
    console.log(self, self ? env['true'] : env['false']);
    return self ? env['true'] : env['false'];
}

lambda_decodeBoolean('one' === 'two')(function() {
    console.log('one is two');
})(function() {
    console.log('one is not two');
})();

lambda_decodeBoolean('one' === 'one')(function() {
    console.log('one is one');
})(function() {
    console.log('one is not one');
})();
Dmitry
fuente
-7

No, SÍ / NO es una forma diferente de referirse a VERDADERO / FALSO (1/0)

Marco
fuente