1. O que é uma proposição lógica
Uma proposição é qualquer frase declarativa que tem exatamente um de dois
valores possíveis: verdadeira (V) ou falsa (F). Nunca os
dois, nunca nenhum dos dois, nunca "depende". Essa restrição parece óbvia, mas é o alicerce
inteiro da lógica formal — e, por extensão, de todo if que você
já escreveu.
Compare estas duas frases:
- "2 + 2 = 4" — é uma proposição. É verificável e é verdadeira.
- "Essa pizza é boa" — não é uma proposição lógica. Depende de quem come.
Em programação você faz esse mesmo julgamento o tempo todo, só que formalizado em código:
toda condição dentro de um if, todo while,
todo retorno de função booleana precisa ser algo que o computador consiga avaliar sem
ambiguidade como true ou false.
Não existe "mais ou menos verdadeiro" — nem em lógica, nem em código.
Proposições costumam ser representadas por letras minúsculas: p,
q, r... Por exemplo,
p = "o usuário está logado" e q =
"o carrinho tem itens". Isso é exatamente o papel de uma variável booleana no seu código.
2. Conectivos lógicos: combinando proposições
Proposições sozinhas são pouco úteis. O poder aparece quando você as combina com conectivos lógicos. Os três fundamentais são a negação, a conjunção e a disjunção — e cada um tem um símbolo matemático e um operador direto na sua linguagem de programação favorita.
| Nome | Símbolo | Lê-se | Operador em JS/C# |
|---|---|---|---|
| Negação | ¬p | "não p" | !p |
| Conjunção (E) | p ∧ q | "p e q" | p && q |
| Disjunção (OU) | p ∨ q | "p ou q" | p || q |
| Disjunção exclusiva | p ⊕ q | "ou p ou q, não os dois" | p !== q (em booleanos) |
| Implicação | p → q | "se p, então q" | !p || q |
Repare que a última coluna não é coincidência nem "parecido" — é a mesma coisa, só que escrita em sintaxe de linguagem de programação em vez de notação matemática. Isso vai ficar mais claro seção por seção.
3. Tabela-verdade: testando todas as combinações possíveis
Uma tabela-verdade lista, de forma exaustiva, o resultado de uma expressão
lógica para todas as combinações possíveis de valores das proposições envolvidas.
Com n proposições, existem 2ⁿ
combinações — com 2 proposições, são 4 linhas; com 3, são 8; e assim por diante.
Comece pela mais simples, a negação (¬p) — só uma proposição, então só 2 linhas:
| p | ¬p |
|---|---|
| V | F |
| F | V |
Agora a conjunção (p ∧ q) — só é verdadeira quando as duas proposições são verdadeiras:
| p | q | p ∧ q |
|---|---|---|
| V | V | V |
| V | F | F |
| F | V | F |
| F | F | F |
E a disjunção (p ∨ q) — verdadeira quando pelo menos uma das duas é verdadeira:
| p | q | p ∨ q |
|---|---|---|
| V | V | V |
| V | F | V |
| F | V | V |
| F | F | F |
Se você já depurou um if com vários &&
e || tentando descobrir por que ele nunca entra no bloco esperado,
você já construiu uma tabela-verdade na cabeça — só que sem o método formal. Escrever a
tabela no papel antes de codificar elimina esse tipo de erro por tentativa e erro.
4. OU-exclusivo (XOR) e implicação, rapidamente
Dois conectivos que aparecem com menos frequência, mas vale conhecer:
- XOR (⊕) — "ou um, ou outro, mas não os dois". Diferente do OU comum, XOR é falso quando as duas entradas são iguais. Aparece em programação em situações como "alternar" um estado (toggle) ou detectar diferença bit a bit.
-
Implicação (→) — "se p, então q".
p → qsó é falsa quandopé verdadeiro eqé falso (uma promessa quebrada). Em todos os outros casos é verdadeira — inclusive quandopé falso, o que costuma soar estranho no início ("se eu não pagar a conta, qualquer coisa pode acontecer e a implicação continua válida").
| p | q | p ⊕ q | p → q |
|---|---|---|---|
| V | V | F | V |
| V | F | V | F |
| F | V | V | V |
| F | F | F | V |
5. A ponte direta com o seu código
Todo if que você escreve avalia uma proposição — ou uma
combinação de proposições com conectivos. O motor de execução da sua linguagem calcula o
valor lógico exatamente como você preencheria uma linha de tabela-verdade.
Sejam:
p = "usuário está logado"
q = "carrinho tem itens"
r = "cupom é válido"
Liberar checkout quando:
(p ∧ q) ∧ (r ∨ ¬temCupom)
const podeChecar =
(usuarioLogado && carrinhoTemItens) &&
(cupomValido || !temCupom);
if (podeChecar) {
liberarCheckout();
}
Não existe tradução ou aproximação acontecendo aqui — &&
é ∧, || é ∨, e
! é ¬. A única diferença é o alfabeto usado
para escrever.
Assim como em matemática, ¬ tem prioridade mais alta que ∧, que por sua vez tem prioridade
mais alta que ∨. Em código isso se repete: ! é avaliado antes
de &&, que é avaliado antes de ||.
Na dúvida, use parênteses — em matemática e em código, eles nunca deixam a expressão errada,
só mais clara.
6. Curto-circuito: uma otimização que vem direto da lógica
Se p já é falso em p ∧ q, o valor da
expressão inteira já está decidido — F, não importa o que
q seja. Toda linguagem de programação moderna usa exatamente
esse raciocínio para parar de avaliar assim que o resultado já está
garantido. É por isso que este código nunca quebra, mesmo quando usuario
é null:
if (usuario && usuario.perfil.ativo) {
// se "usuario" for null/undefined (falsy),
// "usuario.perfil.ativo" NUNCA é avaliado —
// o && já sabe que o resultado é falso
}
Isso não é um truque de linguagem — é consequência direta da tabela-verdade de ∧: uma vez que a primeira coluna dá F, todas as linhas relevantes já têm resultado F, então não há necessidade de olhar a segunda coluna.