Existe uma diferença entre SIM / NÃO, VERDADEIRO / FALSO e verdadeiro / falso no objetivo-c?

154

Simples pergunta realmente; existe uma diferença entre esses valores (e existe uma diferença entre BOOL e bool)? Um colega de trabalho mencionou que eles avaliam coisas diferentes no Objective-C, mas quando observei os typedefs em seus respectivos arquivos .h, YES / TRUE / true foram todos definidos como 1e NO / FALSE / false foram definidos como 0. Existe realmente alguma diferença?

Kevlar
fonte
5
Do ponto de vista prático, não há diferença. Provavelmente, você pode fazer vários truques para demonstrar a diferença, mas geralmente está entrando no território de "comportamento indefinido".
Hot Licks

Respostas:

84

Não há diferença prática, desde que você use BOOLvariáveis ​​como booleanos. C processa expressões booleanas com base na avaliação de 0 ou não de 0. Portanto:

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

significa o mesmo que

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

é por isso que você pode avaliar qualquer tipo ou expressão primitiva como um teste booleano (incluindo, por exemplo, ponteiros). Note que você deve fazer o primeiro, não o último.

Note que não é uma diferença se você atribuir valores obtusos a um chamado BOOLvariável e teste para valores específicos, por isso sempre usá-los como booleans e só atribuí-los a partir de seus #definevalores.

Importante, nunca teste booleanos usando uma comparação de caracteres - não é apenas arriscado, porque someVarpode ser atribuído um valor diferente de zero que não é SIM, mas, na minha opinião, o mais importante, ele falha ao expressar a intenção corretamente:

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

Em outras palavras, use construções conforme pretendidas e documentadas para serem usadas e você se poupará de um mundo de mágoas em C.

Lawrence Dol
fonte
100

Eu acredito que é uma diferença entre boole BOOL, confira esta página para uma explicação do porquê:
http://iosdevelopertips.com/objective-c/of-bool-and-yes.html

Como BOOLé um tipo em unsigned charvez de primitivo, as variáveis ​​do tipo BOOLpodem conter valores diferentes de YESe NO.

Considere este código:

BOOL b = 42;

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

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

A saída é:

b não é NÃO!
b não é SIM!

Para a maioria das pessoas, essa é uma preocupação desnecessária, mas se você realmente deseja um booleano, é melhor usar a bool. Devo acrescentar: o iOS SDK geralmente usa BOOLem suas definições de interface, portanto esse é um argumento a ser seguido BOOL.

Dan J
fonte
5
Mas observe que a implementação C original não tinha boole, portanto, tem sido uma tradição usar um intou charcomo um booleano, às vezes com um #define para esconder a diferença e às vezes não. De fato, não tenho certeza se mesmo os padrões atuais precisam boolser implementados de uma maneira que impeça o exame de sua estrutura interna.
Hot Licks
1
Embora, o primeiro printfconte mentiras. O valor de bnão é YES, é "não zero", que é o que a condição testa. Então você deve ter printf("b is not zero"), que não é necessariamente o mesmo que YES. Nesse caso, bé "não zero" e "não SIM".
Lawrence Dol
Obrigado Lawrence, fiz uma atualização nesse sentido.
Dan J
Na verdade, eu não recebi a segunda saída no Xcode 8.2. Onde eu falho?
Igor Kislyuk
1
@ HotLicks, não há diferença inerente entre 0, não zero e falso e verdadeiro. Desde que o valor pretenda ser um booleano lógico, ele sempre terá essa interface para preservar a compatibilidade binária. Os problemas começam quando você usa não booleanos que parecem booleanos, por exemplo, função de entrada de aplicativo de biblioteca padrão c, retornos principais 0 com êxito, muitos acabam pensando nesse 0 como um booleano, quando na verdade é uma enumeração definida pelo aplicativo ou definida pelo usuário valor, que normalmente espera que seja diferente de zero em terminação anormal.
Dmitry
52

Eu fiz um teste exaustivo sobre isso. Meus resultados devem falar por si:

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

A saída é:

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
fonte
3
[[NSObject] assign] init] não é igual a VERDADEIRO ou SIM. Portanto, o teste para inicialização do objeto com if ([[NSObject] aloc]] init] == ​​TRUE) falhará. Nunca me senti à vontade com uma linguagem que defina um valor "verdadeiro" singular, quando na verdade qualquer valor diferente de zero serve.
usar o seguinte código
3
@SamuelRenkert Eu nunca me senti confortável com um idioma que tenha um valor não-booleano em um ifou em um while. Como ... while("guitar gently weeps")não deveria funcionar ... #
Supuhstar #
@SamuelRenkert também o backdoor Linux que foi encontrado em 2003:if (user_id = ROOT_UID)
Supuhstar
14

Você pode querer ler as respostas para esta pergunta . Em resumo, em Objective-C (da definição em 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
fonte
11

A principal diferença (perigosa!) Entre truee YESestá na serialização JSON.

Por exemplo, temos uma solicitação de servidor do tipo JSON e precisamos enviar true / false no json sence:

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

Em seguida, convertemos para a string JSON antes de enviar como

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

O resultado é

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

Devido à lógica da API, jsonString1pode resultar em um erro.

Portanto, tenha cuidado com os booleanos no Objective-C.

Para resumir, apenas o @YESvalor exato e convertido como @((BOOL)expression)são do __NSCFBooleantipo e convertido para truecom serialização JSON. Quaisquer outras expressões como @(expression1 && expression2)(par @(YES && YES)) são do __NSCFNumber (int)tipo e convertidas 1em JSON.

PS Você pode simplesmente usar booleano com valor de string

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

Há um bug sutil que ninguém mencionou aqui, que eu pensei que incluiria ... mais um erro lógico do que qualquer coisa:

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

portanto, a questão aqui é apenas isso (YES==1)e em C a comparação não é booleana, mas baseada em valor.

porque YESé apenas um #define(em vez de algo intrínseco à linguagem), tem que ter algum valor e 1faz mais sentido.

Grady Player
fonte
Esta é essencialmente a mesma resposta que a de DanJ, ​​de mais de 2 anos antes, com menos detalhes.
Lawrence Dol
@LawrenceDol Eu não sei, ele menciona que YES é apenas # definido para ser 1 e não intrínseco ao idioma, como se estivesse em um idioma de nível superior ... alguém poderia obter valor com isso ... mas bom trollando, com você.
Grady Player
0

Eu acho que eles adicionam SIM / NÃO para ser mais auto-explicativo em muitos casos. Por exemplo:

[button setHidden:YES];

soa melhor que

[button setHidden:TRUE];
Marco
fonte
2
Discordo; os dois leem o mesmo para mim. No entanto, em uma interface do usuário para um leigo, acho que Sim / Não parece melhor.
Lawrence Dol
16
Eu também discordo. Na verdade, ele lê mal devido a não aderência aos padrões não escritos que são usados ​​há anos em outros idiomas. O IE é um excelente exemplo do que acontece quando você falha em seguir um grande número de padrões.
FreeAsInBeer 21/07
1
Metade downvote para 2 respostas imprecisas e meia downvote para assinar suas respostas
fpg1503
-2

Primeiro, vamos examinar o que é verdadeiro e falso e o que lhes dá significado em primeiro lugar.

podemos construir uma estrutura chamada if a então b else c no cálculo lambda da seguinte maneira:

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

Em JavaScript, fica assim:

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

para que IfThenElse seja útil, precisamos de uma função "true" que escolha direita ou esquerda, e faça isso enquanto ignora a outra opção, ou de uma função "false" que escolha a opção "true".

Podemos definir essas funções da seguinte maneira:

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

em JavaScript, fica assim:

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

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

agora podemos fazer o seguinte

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

sendo doThis e doThat (\ a. ()) porque o cálculo lambda não oferece nenhum serviço, como printing / math / strings, tudo o que podemos fazer é não fazer nada e dizer que fizemos (e depois trapacear substituindo-o por serviços em nosso sistema que fornece efeitos colaterais que queremos)

então vamos ver isso em ação.

(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");})();

Esse é um ambiente profundo que poderia ser simplificado se tivéssemos permissão para usar matrizes / mapas / argumentos / ou mais de uma instrução para dividir em várias funções, mas eu quero manter o mais puro possível, me limitando às funções de exatamente um argumento só.

observe que o nome Verdadeiro / Falso não tem significado inerente, podemos renomeá-los facilmente para sim / não, esquerda / direita, direita / esquerda, zero / um, maçã / laranja. Tem significado que, qualquer que seja a escolha feita, é causada apenas pelo tipo de escolha. Portanto, se "ESQUERDA" for impresso, sabemos que o seletor só pode ser verdadeiro e, com base nesse conhecimento, podemos orientar nossas decisões adicionais.

Então, 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
fonte
-7

Não, SIM / NÃO é uma maneira diferente de se referir a VERDADEIRO / FALSO (1/0)

Marco
fonte