C# – sizeof vs Marshal.SizeOf

Depois do PySide – ainda no INDT como já falei em outros posts antigos – e dos bindings JS para o EFL, no meu trabalho atual estamos fazendo bindings para C#, mais especificamente para o Mono.

A princípio é relativamente simples usar código C a partir de C#. De forma resumida, basta declarar uma função em C# dizendo de que biblioteca ele deve importar a função nativa – pense em dlopen/dlsym – e então invocar a função. O Mono cuida de converter os tipos entre o código gerenciado e a função nativa, tanto os parâmetros como o retorno da função. Por exemplo, direto do guia do Mono para interoperabilidade:

[DllImport ("libc.so")]
private static extern int getpid ();

Lógico que isso é apenas o caso mais simples. Dependendo das peculiaridades do tipo a ser convertido, você pode precisar colocar mais informações para orientar o Mono nessa conversão, como o layout das estruturas, o formato de conversão de strings, ou mesmo uma conversão customizada.

Numa dessas customizações tive problemas durante a chamada de algumas funções, onde misteriosamente a pilha de chamada estava sendo corrompida. Depois de alguns testes, vi que as funções que corrompiam os dados envolviam uma estrutura que era passada por valor como argumento. De forma análoga às funções, onde a assinatura que você declara em C# é uma cópia da assinatura nativa e representa o “layout” daquela função na memória, com as estruturas você também faz o mesmo em C#. No caso, essa estrutura era declarada manualmente em C# da seguinte forma:

struct FooBar {
  IntPtr obj;
  bool something;
  bool another_thing;
  int size;
}

Enquanto que em C a estrutura tinha o seguinte formato:

struct Foo_Bar {
  Obj *obj;
  byte something : 1; // Na pratica é um typedef p/ byte
  byte another_thing : 1;
  int size;
}

A princípio tudo parece correto, já que bool no C# é armazenado no espaço de 1 byte, e apesar do bit field em C, cada field “byte” no C ocupava também 1 byte no final, devido ao packing da estrutura.

Ao realizar mais testes, inicialmente usando sizeof no C# e no C, o tamanho e os offsets dos campos estavam iguais entre o C# e C. Foi então que entrou em cena do Marshal.SizeOf. Marshal é uma classe do C# responsável por cuidar da conversão (marshalling) de tipos entre o código gerenciado e o código nativo.

O problema com sizeof era que ele media o uso de memória gerenciada dos tipos. E, curiosamente, o tipo booleano de C# por padrão difere no espaço utilizado entre a memória gerenciada (1) e memória nativa (4), este último corretamente informado pelo Marshal.SizeOf. A solução então foi indicar para o compilador para usar apenas 1 byte ao converter os campos booleanos, da seguinte forma:

struct FooBar {
  IntPtr obj;
  [MarshalAsAttribute(UnmanagedType.U1)] bool something;
  [MarshalAsAttribute(UnmanagedType.U1)] bool another_thing;
 int size;
}

Feito isso, o problema foi corrigido e todos viveram felizes até o próximo bug. 🙂

Anúncios

matplotlib.pyplot em (menos de) 5 minutos

import matplotlib.pyplot as plt

x_data = [1,2,4,5,6,7]
y_data = [x**2 for x in x_data]

# Cria um gráfico de linha e retorna o "artista" para detalhar aquela
# série de dados
line, = plt.plot(x_data, y_data)

# Adiciona uma descrição à série acima
line.set_label('Wowness vs doge count')

# As duas operações acima podem ser repetidas para criar novas séries de
# dados.

# Mostra a caixa de legenda
plt.legend()

# Ao invés de um fundo branco, mostra as linhas de 'grade'
plt.grid()

# Descrição dos eixos
plt.xlabel("Number of doges")
plt.ylabel("Wow, how wowsome am i?")

# Título do gráfico
plt.title("Wow, so much graph!")

# Salva o gráfico num arquivo
plt.savefig('doge_graph.png')

# Mostra uma janela com o gráfico
plt.show()

# Fecha a 'janela' virtual, destruindo o gráfico e liberando a memória
plt.close()

Resultado:

doge_graph

 

PS: Se receber um erro “SyntaxError: Non-ASCII character…” rodando o script acima, eu diria que a solução recomendada é mudar para o python 3 🙂

Credo! Um linter para elixir?

Continuando no tema de Elixir, hoje René Föhring lançou o Credo, um linter “que ensina”. Linters são programas que leem o código fonte e fazem uma análise mostrando potenciais problemas ou pontos de melhoria nesse código, desde formatação até coisas mais escopo de variáveis, etc.

No post de anúncio, René discorre sobre como as ferramentas do Elixir costumam dar as mensagens de erro de maneira informativa, apontando uma possível solução ao invés de apenas culpar o desenvolvedor. Ok, vez por outra ainda aparecem algumas mensagens criptografadas mas a tendência é melhorar cada vez mais.

Seguindo essa linha, o Credo busca dar mensagens bem didáticas, ainda com a opção de mostrar uma explicação mais detalhada sobre o item. Abaixo, segue um exemplo do que ele reportou num pet project que comecei hoje (por isso tão poucos erros 😀 ):

  Warnings - please take a look                                                                                                                                                                 
┃ 
┃ [W] ↗ Parameter `k` has same name as a function in the same module.
┃       lib/raycifex/vector.ex:34:33 (Raycifex.Vector.scalar_mult)
┃ [W] ↗ There should be no calls to IO.inspect/1.
┃       lib/raycifex.ex:5:5 (Raycifex.main)
┃ [W] ↗ There should be no calls to IO.inspect/1.
┃       lib/raycifex.ex:6:5 (Raycifex.main)

Please report incorrect results: https://github.com/rrrene/credo/issues

Analysis took 0.1 seconds (0.06s to load, 0.04s running checks)
17 mods/funs, found 3 warnings.

Only considering priority objects: ↑ ↗ →  (use `--help` for options).

Dessas, apenas o ‘k’ repetido que assumo que realmente foi um desleixo, já que os inspect foram conscientes. Dado um aviso desses, você pode pegar o id do erro – isto é, o arquivo + linha/coluna – e rodar o credo novamente, para ver a explicação detalhada.

Para ver um exemplo mais abrangente e mais informações sobre o projeto, podem ver o post de anúncio, linkado acima.

o/

PS: Parabéns para René, tanto pela ferramenta como pelo nome escolhido, que permitiu a “piada” do título…

[Elixir] Coisas legais sobre Elixir

Um post rápido sobre algumas coisas legais em relação a Elixir, uma linguagem funcional dinâmica implementada em cima da máquina virtual do Erlang, mas com uma sintaxe muito mais agradável/produtiva.

Pattern Matching é lindo

Quem nunca escreveu um método em que precisou fazer uma série de if/elses/switches/dispatching complicado dependendo dos valores dos argumentos? Por exemplo, ao calcular o fatorial de um número em Python:

def factorial(x):
  if (x == 0 or x == 1):
    return 1
  else:
    return x * factorial(x-1)

E se ao invés disso pudesse ser algo assim:

def factorial(0): return 1
def factorial(1): return 1
def factorial(n): return n * factorial(n-1)

Não só para argumentos simples, mas Elixir também suporta para tipos mais complexos como “dicts” ou tuplas. Por exemplo, num projetinho onde implementava (ainda em progresso) o Conway’s Game of Life, eu tinha a seguinte função:

def neighbors(%{:dimensions=>{width, height}}, pos) do ...

Essa função aceitaria mapas – que parecem dicionários de Python – que possuíssem a chave :dimensions (um átomo) apontando para uma tupla com 2 valores e um argumento “pos”. Além de dar match no dicionário, essa definição já faz “unpack” e atribui os valores às variáveis width e height.

Robusta

Chris McCord, criador do Phoenix – “o django/rails de Elixir”, recentemente fez um teste em que um servidor manteve 2 milhões de conexões simultâneas, e só não conseguiu mais por limitação no sistema operacional (ulimit). Fabio Akita postou uma timeline do exercício.

Suporte da comunidade

Tanto o canal #elixir-lang na Freenode, o Slack elixir-lang.slack.com (inclusive o canal brasileiro, com muita gente) e a lista de emails elixir-lang-talk são bastate movimentadas, com bastante gente disposta a tirar dúvidas, etc. Inclusive o criador da linguagem, José Valim (yep, é brasileiro) é bastante ativo.

“Pegadinha”: Cuidado ao encadear múltiplas chamadas de métodos

Num dos testes antigos do PySide, havia uma inocente linha de código com QFile().metaObject().methodCount(), que na nova versão estava causando uma falha de segmentação dentro da Qt. O que estava acontecendo era que o QMetaObject retornado pelo metaObject() estava sendo apagado pelo QFile() criado, invalidando a área de memória que methodCount() tentava acessar. Agora por que diabos ele estava sendo deletado, já que eu chamava o método direto nele? A resposta está no modo como o CPython é implementado, sendo uma máquina virtual de pilha.

Usando o módulo dis nessa linha, temos o seguinte resultado:

0 LOAD_GLOBAL              0 (QFile)
3 CALL_FUNCTION            0
6 LOAD_ATTR                1 (metaObject)
9 CALL_FUNCTION            0
12 LOAD_ATTR                2 (foo)
15 CALL_FUNCTION            0
18 POP_TOP
19 LOAD_CONST               0 (None)
22 RETURN_VALUE

Dissecando instrução por instrução e seus efeitos na pilha, vamos assumir que esteja inicialmente vazia. Apenas as 4 primeiras instrução são necessárias:

  • LOAD_GLOBAL (QFile) – Topo da pilha é a classe QFile
  • CALL_FUNCTION – Remove QFile do topo e coloca o resultado da chamada, no caso, a nova instância de QFile, com refcount 1
  • LOAD_ATTR(metaObject) – Remove a instância de QFile do topo (decrementa o refcount) e coloca o resultado de getattr(instância, ‘metaObject’) no topo. Nesse caso, o resultado é um “bound method” A chamada a getattr incrementa a referência da instância de QFile, logo ela não morre.
  • CALL_FUNCTION – Remove o metodo metaObject do topo e coloca o resultado, no caso a instância de QMetaObject retornada. Ao remover o método, a referência à instância de QFile é removida, chegando a 0. Então o destrutor do binding chama o destrutor de C++, que por sua vez deleta o objeto C++ do QMetaObject, invalidando o ponteiro usado pelo binding.

Ou seja, devido essas instruções, não se pode garantir que um objeto criado anonimamente numa chamada de metodo e usado imediatamente irá estar “vivo” em chamadas subsequentes.

Vale notar que esse problema aparece em outras implementações de Python baseadas no CPython, como o Stackless e o Unladen Swallow. Implementações que usam outros tipos de máquina virtual como o Jython, IronPython e Pypy não sofrem desse problema.

Lambdas em laços for

Duas vezes num espaço de pouco mais de poucas semana me deparei com duas situações em que o programador era vítima de uma característica pouco conhecida da instrução lambda de python.

Ambas as situações envolviam usar lambda dentro de um laço for para criar funções dinamicamente de acordo com o valor fornecido pelo for naquela iteração. Seria algo mais ou menos assim:

for x in range(10):
algo_assincrono.connect(lambda : foobar(x))

No caso, o programador queria que a funcao foobar fosse chamada para cada x gerado no for, enquanto que na prática a função é sempre chamada com o último valor atribuído a x. Isso acontece porque a instrução lambda de python não é exatamente igual às outras lambdas de outras linguagens.

Em python, lambda é apenas uma mandeira simples de encapsular uma expressão dentro de uma função anônima, sem resolver os nomes das variáveis em tempo de definição. Ou seja, lambdas de python não possuem um escopo (espaço de nomes) próprio, trabalhando no escopo em que foram definidas. E como o laço for também não cria um espaço de nomes próprio, a variável x no caso acima estará com o último valor atribuído a ela até o momento da execução do lambda.

Uma alternativa para esse problema é usar aplicação parcial de funções, disponível como a função partial no módulo functools. Ela trabalha recebendo como primeiro parâmetro a função alvo e em seguida os argumentos que devem ser aplicados parcialmente, retornando uma função que receberá apenas os argumentos restantes. Por exemplo:

>>> def foo(x,y,z):
... return x+y+z
...
>>> foo(3)
Traceback (most recent call last):
File "", line 1, in
TypeError: foo() takes exactly 3 arguments (1 given)
>>> from functools import partial
>>> bar = partial(foo, 3)
>>> bar(4,5)
12
>>> bar(4)
Traceback (most recent call last):
File "", line 1, in
TypeError: foo() takes exactly 3 arguments (2 given)
>>> bar(0,0)
3
>>>

Voltando para o exemplo inicial, utilizando partial, ficaria assim:
for x in range(10):
algo_assincrono.connect(partial(foobar, x))

Zen do Python na prática

– Como é o jeito padrão de implementar árvore em python?

– Rapaz, até onde eu sei cada um implementa do jeito que precisa.

–  Sim, mas não tem um jeito “padrão”?

– Hum, acho que não.

– Então eu vou ter que implementar essa árvore e disponibilizar p/ cara p/ ele herdar dela e…

– Porque você precisa de uma árvore?

– Ah, eu tenho plugins e eles precisam retornar os menus e submenus na forma de uma árvore.

– Por que não diz ao cara apenas que ele precisa ter um atributo ‘children’ com uma lista dos filhos que por sua vez podem ter também o atributo children e assim até chegar na folha da ‘árvore’. Dessa forma ele fica livre para implementar do jeito que quiser.

– É, boa idéia…

É mais fácil pedir desculpa que pedir permissão

“Com mais dinheiro resolveremos nossos problemas!”

Trecho de um artigo no blog Productivity501 sobre um projeto de aumento nas taxas no estado de Michigan:

The thought of “if we only had more money we could fix our problems” is prevalent in government, business and personal life.  If your focus is on getting more money you will often overlook solutions that actually solve the problem.  Worse still, the “money” solutions often turn out to create new problems that are worse that what you were originally trying to fix.

Em livre tradução:

A idéia de que “se nós tivéssemos mais dinheiro nós poderíamos consertar nossos problemas” é predominante no governo, negócios, e vida pessoal. Se seu foco é em conseguir mais dinheiro você geralmente vai ignorar soluções que na prática resolvem o problema. Pior ainda, as soluções de “dinheiro” normalmente acabam criando novos problemas que são piores que os problemas originais.

Não poderia concordar mais.

Raycife: Agora com sombras

Apesar de ter aumentado consideravelmente a granularidade (tá parecendo coisa de z-buffer ou algo do tipo), corrigi um bug besta pelo qual as sombras não estavam aparecendo: O raio de luz estava com a direção invertida (luz – ponto_de_verificação, e não ponto_de_verificação – luz)…

Abaixo, o resultado: 100×100 pixels e 100 raios/pixel (26 minutos, mas usando o computador enquanto processava):

Próximos passos: resolver essa bronca de granularidade e adicionar reflexão especular.