hisham hm

🔗 A lógica brasileira, ou a brasilidade da filosofia

Antes de começarmos, uma expressão que não se ouve todo dia: “a lógica brasileira”. Quando eu lhe digo “lógica brasileira”, o que vem à sua cabeça? Voltaremos a isso depois.

Esses dias eu estava conversando com uma amiga sobre escolas de filosofia, coisas que a gente lê e tenta estudar. Comentei com ela que tinha a impressão que aqui no Brasil quando eu falo com as pessoas sobre filosofia, a referência parece ser sempre a tal da filosofia continental — alemães do século XIX, franceses do século XX, de Schopenhauer a Derrida, essas coisas — enquanto os americanos seguem a tradição analítica dos ingleses. Isso nos levou a pensar sobre filosofia e lugares, aí ela comentou de um livro “ressentido, mas interessante” chamado Crítica da Razão Tupiniquim, de Roberto Gomes. Procurei um pouco a respeito do livro e achei algumas resenhas. Em uma delas, o argumento central do autor parece ser resumido dessa forma:

O fato é que as nossas academias produzem historiadores da filosofia, comentadores… mas não exatamente filósofos.

De fato, é muito mais comum ver gente falando dos grandes nomes de fora do que daqui, e nas prateleiras da seção de filosofia das livrarias, quando vejo nomes brasileiros, são em livros discutindo os filósofos estrangeiros.

Isso nunca me chamou a atenção em particular, talvez por não ter uma visão nacionalista sobre as coisas, talvez por não ter sequer expectativas a respeito. Mas o fato do assunto ter sido trazido me fez pensar a respeito. Na verdade, me fez pensar mais sobre o porquê da percepção da tal “falta de uma filosofia nacional”. Afinal, se os americanos, com sua escola do pragmatismo, são “continuadores” da filosofia dos ingleses e não meros “comentadores”, por que então nós, latino-americanos, não poderíamos nos considerar o mesmo em relação à tradição continental?

Acho que é mais uma questão mais de auto-imagem do que qualquer coisa, o que me remeteu ao excelente blogpost com 65 impressões de um francês sobre o Brasil que circulou essa semana (recomendo muito a leitura, faz muito bem ver o tal “olhar de fora”). Em particular lembrei do ponto 46, um item mais sério no meio de vários outros mais divertidos:

46. Aqui no Brasil, o brasileiros acreditam pouco no Brasil. As coisas não podem funcionar totalmente ou dar certo, porque aqui, é assim, é Brasil. Tem um sentimento geral de inferioridade que é gritante. Principalmente a respeito dos Estados Unidos. To esperando o dia quando o Brasil vai abrir seus olhos.

Dito assim parece uma visão simplista, parte óbvia e parte ufanista com o lance do Brasil “abrir seus olhos”. Mas lembro sempre de uma anedota interessante que ilustra de forma cabal essa questão da auto-imagem. No excelente Coding Places, do meu amigo Yuri Takhteyev, que apresenta uma visão sociológica sobre a globalização através do prisma do mundo do desenvolvimento de software no Rio de Janeiro, ele faz uma observação sobre como nós brasileiros usamos a palavra “nacional”. Lembrando que em inglês “national” não se usa como usamos “nacional” aqui. Lá, “national” só se usa em coisas do tipo “national security” e “national anthem“, é pra falar da Naçããão mesmo. Pros usos mundanos eles usam “domestic” (do mesmo jeito que falamos “voo doméstico” aqui). Do livro:

The Portuguese phrase Antônio uses to describe Lua in the end—”um software nacional”—is remarkably ambiguous. While it can be literally translated as “national software”, such a translation would connote a lot more patriotic pride than the Portuguese word “nacional” typically implies. Products that are described with this adjective are often understood to be local substitutes for foreign products that are either not available or more expensive. (For example, a visitor to a Brazilian bar may be offered a choice between an expensive “whisky importado” and a cheaper “whisky nacional.”)

Quando li esse trecho, me surpreendi ao notar que sim, sem nem estar escrito quais são os whiskies no menu, vamos imediatamente assumir que o importado é melhor e que “nacional” implicitamente significa pior. Acaba que ao adjetivarmos algo como “nacional” ou “brasileiro”, na imensa maioria das vezes acabamos inconscientemente depreciando a coisa, exceto talvez em se tratando das artes (”música brasileira”, “literatura brasileira”).

O que nos traz à “lógica brasileira”. O que seria uma lógica brasileira? Como bom brasileiro, posso até imaginar de bate-pronto umas piadinhas pra fazer em relação a essa definição e suponho que você também.

Mas o motivo pelo qual eu pensei nesse termo foi por estar tentando lembrar de algum trabalho relevante de filosofia feito no Brasil. Lembrei que, apesar de nas artes e na psicologia (duas áreas com as quais tenho contato indireto por causa de pessoas que provavelmente estão lendo esse post aqui :) ) as referências de filosofia serem da escola continental (e onde as referências nacionais pendem mais para a psicanálise), um trabalho de filosofia de que eu tenho conhecimento e que é feito no Brasil é no campo da filosofia analítica… e que há uma escola de estudo de lógica não-clássica que é mundialmente conhecida como, sim, lógica brasileira.

Trata-se do trabalho do curitibano Newton da Costa, um dos fundadores do estudo de lógica paraconsistente, do seu aluno Walter Carnielli (co-autor de um livro-texto de lógica que é usado em lugares como Cambridge, Carnegie Mellon e afins) e dessa galera toda que estuda lógica na Unicamp. (E sim, eu notei que acabei de apelar à referência das universidades “de fora” pra validar a relevância do trabalho do Carnielli.)

Mas o que seria essa “lógica brasileira”?

Helio Oiticica, Metaesquema II, 1958

Bom, relembrando que lógica clássica é aquela tipo “Todos os homens são mortais, Sócrates é mortal, logo…”, o que é conhecido como “lógica brasileira” é um tipo de lógica não-clássica, isto é, que não segue todos os axiomas da lógica aristotélica. Talvez você pense: “mas peraí, se não seguir todas as regrinhas da lógica, ela não ‘quebra’?”. Essa é a ideia. Mais especificamente, é um tipo de lógica paraconsistente, que é justamente um tipo de lógica que, ao contrário da lógica clássica, permite a existência de contradições. Como diz a Wikipedia:

Paraconsistent logic is the subfield of logic that is concerned with studying and developing paraconsistent (or “inconsistency-tolerant”) systems of logic.

Sinceramente, eu acho pensar que a “lógica brasileira” seja um tipo de lógica que dá espaço à contradição e que seja tolerante à inconsistência, poeticamente apropriado.

Acho que o Brasil só vai “abrir seus olhos” como sonha nosso amigo francês quando nos dermos conta e aceitarmos essa nossa natureza, com suas contradições e inconsistências. Se até um rigoroso sistema de lógica formal pode ser pensado e entendido dessa forma, imagine o resto. Aí está a brasilidade da filosofia, e talvez até a filosofia da brasilidade.

🔗 Java: if you have trouble declaring a static hashmap…

Java (as of version 6, aka 1.6) does not allow you to declare a static HashMap as conveniently as an array. Still, you have the alternative of using a static block in your class to add fields. Take this example:

import java.util.HashMap;

public class StaticHashMapTest {
	private final static HashMap constants = new HashMap();
	static
	{
		constants.put("A", "The Letter A");
		constants.put("B", "The Letter B");
		constants.put("C", "The Letter C");
	}
	/* Rest of your class that needs to know the consts */
}

This works fine. But then you want to map something a little more complex than a string to another string. And I don't mean something very complex... just, say, a string to a string and an integer (yes, you'd like to use some kind of "pair object", but it looks like Java does not have it).

So you go and try to do things The Java Way (tm) and create a tiny class just to hold your two values:

import java.util.HashMap;

public class StaticHashMapTest {

	private class Pair {
		final String name;
		final int number;
		public Pair(String name, int number) {
			this.name = name;
			this.number = number;
		}
	}

	private final static HashMap constants = new HashMap();
	static
	{
		constants.put("A", new Pair("The Letter A", 123));
		constants.put("B", new Pair("The Letter B", 456));
		constants.put("C", new Pair("The Letter C", 789));
	}
	/* Rest of your class that needs to know the consts */
}

This should suffice, right? I even made the Pair class private to my class, to ensure good information hiding (that's what Java is all about, right?). Turns out this fails to compile:

StaticHashMapTest.java:18: non-static variable this cannot be referenced from a static context
      constants.put("A", new Pair("The Letter A", 123));
                         ^
StaticHashMapTest.java:19: non-static variable this cannot be referenced from a static context
      constants.put("B", new Pair("The Letter B", 456));
                         ^
StaticHashMapTest.java:20: non-static variable this cannot be referenced from a static context
      constants.put("C", new Pair("The Letter C", 789));
                         ^
3 errors

The error messages say that my "new" operators are failing due to the use of the "this" variable, which is not there at all! But hey, we can call "new" from a static context, can't we? We just did that when declaring the HashMap itself.

It turns out that the problem is that we're using an inner class. Objects from inner classes hold a "this" reference to their parent object (yes, as in myInnerObject.this.myParentAttribute... go figure), hence the trouble with the implicit "this" reference.

You have to make it a static inner class, which means it doesn't know anything about the enclosing class. Yes, that's yet another meaning for the word "static" in programming. Due to this peculiar meaning, inner classes are the only context where you can use the "static" qualifier to a class declaration in Java.

This, therefore, works:

import java.util.HashMap;

public class StaticHashMapTest {

	private static class Pair {
		final String name;
		final int number;
		public Pair(String name, int number) {
			this.name = name;
			this.number = number;
		}
	}
	private final static HashMap constants = new HashMap();
	static
	{
		constants.put("A", new Pair("The Letter A", 123));
		constants.put("B", new Pair("The Letter B", 456));
		constants.put("C", new Pair("The Letter C", 789));
	}
	/* Rest of your class that needs to know the consts */
}

And that's Java for you.

🔗 Tethering no Linux com celular Nokia, conectando no 3G da TIM

E eis que consegui conectar o notebook à internet usando o celular Nokia (N85) e um cabo USB. (Ok, tive que catar instruções lendo no browserzinho do celular, mas rolou!)

Condensando aqui as instruções para facilitar minha vida da próxima vez:

1) Configurar o celular para conectar em modo “PC Suite” (normalmente eu deixo em “Mass storage”). No celular: Tools → Settings → Connection→ USB → USB Connection Mode: “PC Suite”

2) Plugar o celular na USB. Devem aparecer linhas mais ou menos assim no log do kernel (/var/log/kernel, dmesg)

usb 2-1.2: new high speed USB device using ehci_hcd and address 5
usb 2-1.2: New USB device found, idVendor=0421, idProduct=0094
usb 2-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 2-1.2: Product: N85
usb 2-1.2: Manufacturer: Nokia
usb 2-1.2: SerialNumber: 356808020426058
usb 2-1.2: configuration #1 chosen from 1 choice
cdc_acm 2-1.2:1.1: ttyACM0: USB ACM device
usbcore: registered new interface driver cdc_acm
cdc_acm: v0.26:USB Abstract Control Model driver for USB modems and ISDN adapters
NET: Registered protocol family 35
cdc_phonet: probe of 2-1.2:1.12 failed with error -22
usbcore: registered new interface driver cdc_phonet
usbcore: registered new interface driver cdc_ether
usb 2-1.2: bad CDC descriptors
usbcore: registered new interface driver rndis_host
usb 2-1.2: bad CDC descriptors
usbcore: registered new interface driver rndis_wlan

O principal ali é o “ttyACM0”, que indica que criou o device. Conferir que existe agora um arquivo /dev/ttyACM0

3) Arquivo /etc/ppp/peers/tether:

ttyACM0 460800 crtscts
connect '/usr/sbin/chat -v -f /etc/ppp/chat-tether'
noauth

O nome “tether” é arbitrário, pode ser qualquer um (será usado abaixo), mas o pppd parece realmente querer os arquivos no diretório /etc/ppp/peers.

4) Arquivo /etc/ppp/chat-tether:

TIMEOUT 5
ECHO ON
ABORT BUSY
ABORT ERROR
ABORT 'NO CARRIER'
ABORT VOICE
ABORT 'NO DIALTONE'
ABORT 'NO DIAL TONE'
ABORT 'NO ANSWER'
ABORT DELAYED
TIMEOUT 12
'' ATZ
OK AT+CGDCONT=1,"IP","tim.br"
OK ATD*99#
CONNECT ''

Note a APN da operadora TIM ali. Para outras operadoras, mudar ali de acordo (gprs.oi.com.br, claro.com.br, zap.vivo.com.br).

O nome do arquivo deve ser o mesmo referenciado dentro do arquivo /etc/ppp/peers/tether acima.

5) Rodar: sudo pppd call tether

Se tudo for bem, aparecerá algo assim no /var/log/messages:

Jul 16 21:24:32 (none) pppd[4746]: pppd 2.4.4 started by root, uid 0
Jul 16 21:24:33 (none) chat[4747]: timeout set to 5 seconds
Jul 16 21:24:33 (none) chat[4747]: abort on (BUSY)
Jul 16 21:24:34 (none) chat[4747]: abort on (ERROR)
Jul 16 21:24:34 (none) chat[4747]: abort on (NO CARRIER)
Jul 16 21:24:34 (none) chat[4747]: abort on (VOICE)
Jul 16 21:24:34 (none) chat[4747]: abort on (NO DIALTONE)
Jul 16 21:24:34 (none) chat[4747]: abort on (NO DIAL TONE)
Jul 16 21:24:34 (none) chat[4747]: abort on (NO ANSWER)
Jul 16 21:24:34 (none) chat[4747]: abort on (DELAYED)
Jul 16 21:24:34 (none) chat[4747]: timeout set to 12 seconds
Jul 16 21:24:34 (none) chat[4747]: send (ATZ^M)
Jul 16 21:24:34 (none) chat[4747]: expect (OK)
Jul 16 21:24:34 (none) chat[4747]: ATZ^M^M
Jul 16 21:24:34 (none) chat[4747]: OK
Jul 16 21:24:34 (none) chat[4747]:  -- got it
Jul 16 21:24:34 (none) chat[4747]: send (AT+CGDCONT=1,"IP","tom.br"^M)
Jul 16 21:24:34 (none) chat[4747]: expect (OK)
Jul 16 21:24:34 (none) chat[4747]: ^M
Jul 16 21:24:34 (none) chat[4747]: AT+CGDCONT=1,"IP","tom.br"^M^M
Jul 16 21:24:34 (none) chat[4747]: OK
Jul 16 21:24:34 (none) chat[4747]:  -- got it
Jul 16 21:24:34 (none) chat[4747]: send (ATD*99#^M)
Jul 16 21:24:34 (none) chat[4747]: expect (CONNECT)
Jul 16 21:24:34 (none) chat[4747]: ^M
Jul 16 21:24:34 (none) chat[4747]: ATD*99#^M^M
Jul 16 21:24:34 (none) chat[4747]: CONNECT
Jul 16 21:24:34 (none) chat[4747]:  -- got it
Jul 16 21:24:34 (none) chat[4747]: send (^M)
Jul 16 21:24:34 (none) pppd[4746]: Serial connection established.
Jul 16 21:24:34 (none) pppd[4746]: Using interface ppp0
Jul 16 21:24:34 (none) pppd[4746]: Connect: ppp0 <--> /dev/ttyACM0
Jul 16 21:24:37 (none) pppd[4746]: local  IP address 189.67.100.239
Jul 16 21:24:37 (none) pppd[4746]: remote IP address 10.6.6.6

E deve aparecer um ppp0 no ifconfig:

ppp0      Link encap:Point-to-Point Protocol
          inet addr:189.67.100.239  P-t-P:10.6.6.6  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1
          RX packets:8938 errors:0 dropped:0 overruns:0 frame:0
          TX packets:7998 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:3
          RX bytes:7405264 (7.0 Mb)  TX bytes:1018670 (994.7 Kb)

6) Estabelecer o default gateway: sudo route add default gw 10.6.6.6

Conferir com o comando route:

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.6.6.6        *               255.255.255.255 UH    0      0        0 ppp0
default         10.6.6.6        0.0.0.0         UG    0      0        0 ppp0

7) Configurar o DNS (por exemplo, com o DNS público do Google). Arquivo /etc/resolv.conf:

nameserver 8.8.8.8

Feito isso, o acesso à internet deve estar funcionando normalmente no computador!

🔗 Crash-course sobre gdb: decifrando segmentation faults

Como não ficar no escuro em caso de segmentation fault:

1) Compile o programa com símbolos de depuração

Use a flag “-g” do gcc para compilar o programa com símbolos de depuração. Certifique-se que todos os objetos estão compilados com “-g”. Você pode precisar dar “make clean”.

2) Seu ambiente deve estar com “core dump” habilitado

Ao ocorrer um “segmentation fault”, o Linux pode gerar um arquivo que é imagem da memória do programa na hora que ele “deu pau”, o chamado “core dump” (curiosidade: o “core dump” tem esse nome por causa da memória de ferrite dos anos 1950-1970, que era chamada de “magnetic-core memory“, ou simplesmente “core”). Com o arquivo de “core dump”, podemos fazer a análise post-mortem do processo e descobrir por que ele explodiu.

Digite “ulimit -c” no seu shell. Se ele retornar “0”, o sistema não irá gerar os arquivos “core”. Digite “ulimit -c unlimited” para remover a restrição de tamanho aos arquivos core. Esta é uma configuração por processo, que é herdada pelos processos filhos (portanto, só vale no terminal onde foi digitada). Para torná-la “permanente”, você pode configurar isso no seu .bash_profile, .zshrc ou equivalente.

3) Rodando o gdb

Com o binário e o core dump na mão, rode o gdb:

gdb ./meu_programa_bugado core

(Dependendo da distro, o arquivo core pode ter o número do processo no seu nome, como “core.1234”)

4) Comandos básicos do gdb

Com esses comandos básicos, podemos analisar os dados de um core dump:

  • bt - (ou backtrace), mostra a pilha de execução, indicando o arquivo e linha onde seu programa caiu. bt full mostra também as variáveis locais de cada função na pilha.
  • up e down - sobem e descem níveis na pilha. Útil para usar o comando:
  • print expressão - o comando print é bastante poderoso: ele pode exibir variáveis e usar boa parte da sintaxe de C. Use-o para inspecionar seus dados:
    • print x
    • print ((char*)x)[4]
    • print &x
    • print x->y
  • quit - porque eu sempre erro e escrevo exit!

Há muito mais que se pode aprender sobre o gdb — é um debugger completo capaz de depurar o programa enquanto roda (gdb -p pid), lidar com threads, etc… mas esse conjunto pequeno de comandos apresentado aqui já é uma mão na roda para decifrar os “segmentation faults”!

🔗 Git Cheat Sheet

I have a hard time memorizing certain unfrequent tasks on Git. I’ll write them down here as I learn them so I can look it up later.

Undo a commit

If you just made a commit (perhaps typing git commit -a too eagerly) and realize you made a mistake, use this to uncommit the modified code, so it shows as “modified:” in git status again and appears again in git diff:

git reset HEAD~

I even added an alias git undo-commit, like this:

git config --global alias.undo-commit 'reset HEAD~'

Getting the last commit from another branch

When working in an alternative branch, you can retrieve the latest commit from another branch with this:

git cherry-pick other-branch

Example:

$ git checkout anotherBranch
$ git branch
* anotherBranch
  master
$ edit some files...
$ git commit -a
$ git checkout master
$ git branch
  anotherBranch
* master
$ git cherry-pick anotherBranch

Interactively select which edits should be committed

After making several edits across files, sometimes you want to add them as separate commits. Committing files separately is easy, but sometimes various edits in the same file should be different commits (or some changes to a file are ready to be committed but others are not). To commit part of the changes to a file, use:

git add -p

From the manual:

“Interactively choose hunks of patch between the index and the work tree and add them to the index. This gives the user a chance to review the difference before adding modified contents to the index. This effectively runs add –interactive, but bypasses the initial command menu and directly jumps to the patch subcommand.”


Follow

🐘 MastodonRSS (English), RSS (português), RSS (todos / all)


Last 10 entries


Search


Admin