domingo, 31 de maio de 2009

Funções e expressões Lambda no C++ 0x - Parte 2


Todas as funções lambdas apresentadas no post anterior não possuiam membro de dados. A utilização de membro de dados pode ser feita por meio da captura de variáveis locais que é realizada pelo introdutor lambda ([]). Neste introdutor é possível especificar uma lista de captura (capture-list) como demonstrado no Código 1.

Código 1

int main()
{
vector v;

for (int i = 0; i < 10; ++i)
v.push_back(i);

int x = 0;
int y = 0;

cout << "Input: ";
cin >> x >> y;

v.erase(remove_if(v.begin(), v.end(), [x, y](int n) { return x < n && n < y; }), v.end());

for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

cout << endl;
}



Um exemplo da execução do programa do Código 1 seria
Input: 4 7
0 1 2 3 4 7 8 9



É importante salientar que apesar do corpo da função lambda estar lexicamente no escopo de main() , ela esta conceitualmente fora do escopo de main(). Sendo assim, não é possível usar variáveis locais declaradas em main() sem “captura-las”.



Todas as capturas são feitas por valor e apenas cópias das variáveis são armazenadas na função. Isso implica em algumas conseqüências importantes: (a) não é possível modificar as cópias capturadas, pois por default a chamada da função objeto é const, (b) atualizações nas variáveis locais não serão refletidas nas cópias capturadas. Mais a frente neste post irei explicar como capturar variáveis por referência.


Ao invés de informar todas as variáveis que deseja capturar, é possível especificar a captura de todas as variáveis locais. A syntax para isso é o introdutor lambda [=]. Usando o exemplo do código 1, bastaria substituir a linha 14 para:


v.erase(remove_if(v.begin(), v.end(), [=](int n) { return x < n && n < y; }), v.end());


Usando este recurso, o compilador irá fazer a captura por valor de todas as variáveis de main() (no exemplo x e y)


Caso seja necessário modificar as variáveis capturadas, pode-se modificar a chamada da função lambda de const para non-const. Para isso deve-se usar o já conhecido modificador mutable. O Código 2 mostra um exemplo deste recurso.

Código 2

int main()
{
vector v;

for (int i = 0; i < 10; ++i)
v.push_back(i);

int x = 1;
int y = 1;

for_each(v.begin(), v.end(), [=](int& r) mutable {
const int old = r;
r *= x * y;
x = y;
y = old;

});

for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

cout << endl;
cout << x << ", " << y << endl;
}


O exemplo mostrado no Código 2 multiplica cada elemento de v com os 2 elementos anteriores.
Sua execução mostraria
0 0 0 6 24 60 120 210 336 504
1, 1


É importante ressaltar que modificações nas variáveis capturadas não são refletidas nas variáveis locais. Caso seja necessário refletir as modificações das variáveis capturadas sobre suas correspondentes locais, isso é alcançado por meio da captura por referência. A syntax para a captura por referência é o introdutor lambda [&x, &y, &z]. A declaração anterior deve ser lida como referência para x, y e z e não endereço de x, y e z. O Código 3 mostra o Código 2 modificado para usar variáveis capturadas por referência.

Código 3

int main() {

vector v;

for (int i = 0; i < 10; ++i)
v.push_back(i);

int x = 1;
int y = 1;

for_each(v.begin(), v.end(), [&x, &y](int& r) {
const int old = r;
r *= x * y;
x = y;
y = old;
});

for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

cout << endl;
cout << x << ", " << y << endl;

}


O exemplo mostrado no Código 3 multiplica cada elemento de v com os 2 elementos anteriores.
A execução do Código 3 mostraria
0 0 0 6 24 60 120 210 336 504
8, 9


Observe as diferenças do Código 3 com o Código 2: (i) O introdutor lambda [&x, &y], (ii) a retirada do modificador mutable e (iii) as variáveis locais tendo valores 8 e 9 ao final da execução, refletindo as modificações dentro da função lambda. Também é possível capturar todas as variáveis locais por referência. usando o introdutor lambda [&]

Finaliza aqui o papo sobre funções lambdas. Acho que para um post introdutório o que já foi dito ate aqui é suficiente. Tem muito mais coisas interessantes sobre funções lambdas que não abordei aqui. Para um estudo mais extensivo sobre esta funcionalidade recomendo a leitura da última versão da especificação que pode ser encontrado aqui.

Irei continuar postando sobre o C++ 0x. Percebi que a quantidade de material na língua portuguesa é mínima e irei tentar dar minha contribuição.

[]’s

Leonardo X. T. Cardoso

quarta-feira, 27 de maio de 2009

Funções e expressões Lambda no C++ 0x


Um dos recursos mais importantes do próximo padrão C++ que ainda esta em desenvolvimento é a chamada função lambda.Expressões lambdas definem e constroem implicitamente funções objetos sem nome que na prática se comportam como as já conhecidas funções objetos. Como um trecho de código vale mais do que mil palavras, no Código 1 abaixo pode-se ver a utilização básica de uma função lambda.


Código 1

int main()
{
vector v;

for (int i = 0; i < 10; ++i)
v.push_back(i);

for_each(v.begin(), v.end(), [](int n) { cout << n << " "; });

cout << endl;
}



O [] é chamado introdutor lambda (lambda-introducer) e informa o início de uma função lambda. A declaração do parâmetro lambda é representado por int n e o corpo da função lambda é { cout << n << “ “;. Por default uma função lambda retorna void. Segue abaixo no Código 2 como seria este mesmo código escrito no padrão atual do C++ usando o tradicional funtor.


Código 2


struct Functor {
void operator()(int n) const
{
cout << n << " ";
}

};

int main()
{
vector v;
for (int i = 0; i < 10; ++i)
v.push_back(i);

for_each(v.begin(), v.end(), Functor());

cout << endl;
}


Alguns de vocês já devem estar se perguntando se é permitido colocar vários comandos dentro de uma função lambda. A resposta é sim e um exemplo é mostrado no Código 3:


Código 3


int main()
{
vector v;

for (int i = 0; i < 10; ++i)
v.push_back(i);

for_each(v.begin(), v.end(), [](int n) {
cout << n;
if (n % 2 == 0)
cout << " even ";
else
cout << " odd ";
});

cout << endl;
}



Ao avaliar o Código 3 você já pode estar imaginando a “macarronada” que um programador pode fazer no código ao usar expressões lambda. Se já era fácil fazer códigos ilegíveis agora ficará ainda mais simples. Acredito que em breve vão lançar o Obfuscated C++ 0x Code Contest. Pode ser que criem coisas mais assustadoras do que o já conhecido International Obfuscated C Code Contest (http://www.ioccc.org/).

Antes que você me pergunte, expressões lambdas podem retornar qualquer tipo de dados. Se o corpo de sua função é do tipo { return expr; }, o tipo de retorno será automaticamente deduzido para o tipo de expr. No Código 4 é mostrado um exemplo:


Código 4


int main()
{
vector v;

for (int i = 0; i < 10; ++i)
v.push_back(i);

deque d;

transform(v.begin(), v.end(), front_inserter(d), [](int n) { return n * n * n; });

for_each(d.begin(), d.end(), [](int n) { cout << n << " "; });

cout << endl;
}



No Código 4 o tipo de n*n*n é int e por isso a função lambda retorna int. Lambdas com expressões mais complexas não são capazes de deduzir o tipo de retorno e por isso o programador deve informar explicitamente. O Código 5 ilustra como isso é feito:

Código 5

int main()
{
vector v;

for (int i = 0; i < 10; ++i)
v.push_back(i);

deque d;

transform(v.begin(), v.end(), front_inserter(d), [](int n) -> double {
if (n % 2 == 0)
return n * n * n;
else
return n / 2.0;
});

for_each(d.begin(), d.end(), [](double x) { cout << x << " "; });

cout << endl;
}


O trecho “>- double” é a cláusula opcional de tipo de retorno lambda. O motivo da cláusula não ficar mais a esquerda como acontece com todos os tipos de funções C é que [ ] deve ficar antes para informar ao compilador o início da função lambda. Se o programador não escrever a clausula de tipo de retorno, o compilador provavelmente vai gerar um warning para cada return.

Hoje termino a primeira parte do estudo de expressões lambda. No próximo post irei mostrar expressões lambdas que contem membros de dados.

Referência


O artigo original fonte de inspiração deste post e origem dos código de exemplo pertence ao blog do Visual C++.


[]’s


Leonardo X. T. Cardoso

terça-feira, 26 de maio de 2009

Placa "Live Free or Die" UNIX completa 20 anos

Quem do mundo Unix nunca viu a famosa placa Live Free or Die UNIX em canto pela internet ? Se você nunca viu, segue uma das versões abaixo.


Pois bem, esta placa completou 20 anos em 2009 e foi criada pelo não menos famoso John “Maddog” Hall. Alguns dizem que esta é a placa de carro mais celebrada do estado americano de New Hampshire. Pelo menos no mundo nerd eu não duvido. :)

Segue abaixo uma foto do Maddog ao lado de seu Jeep Wrangler e a placa original.




PS: New Hampshire é um dos poucos estados americanos onde não é cobrado tax. Parece que ele também gosta de fazer suas compras livre de tax. ☺


[]'s

Leonardo X. T. Cardoso

Sun Microsystems anuncia maior App Store do Mundo

De acordo com o CEO da Sun Jonathan Schwarts, a próxima tacada da Sun será a construção de uma App Store que será a maior do mundo deixando a App Store da Apple no chinelo. Esta App Store venderá aplicativos Java com o foco em usuários domésticos. A meta é que o número de usuários ultrapasse 1 bilhão.

Os desenvolvedores vão submeter seus aplicativos no website da App Store e a Sun vai avaliar o conteúdo e segurança antes que seja apresentado ao público. Os ganhos da Sun serão provenientes das taxas de distribuição que serão cobradas de cada aplicativo vendido. Funcionamento parecido com o da App Store da Apple.

O potencial de mercado da Sun é enorme e leva em conta os 4.5 bilhões de computadores, telefones celulares e outros dispositivos que tem suporte Java. Comparando com a App Store da Apple, esta já teve cerca de 1 bilhão de downloads sendo que existem “apenas” cerca de 21 milhões de Iphones em utilização.

Levando em conta estes números, pode ser que a App Store da Sun realmente deixe a da Apple no chinelo em termos de número de usuários e faturamento. Mas isso não será simples e precisará da utilização em massa do serviço pelos usuários de computadores domésticos e smartphones.

Minha opinião é que a Sun pode se dar muito bem se conseguirem construir um bom serviço para downloads de aplicativos para celulares. Lembrando que isso não vai ser fácil dada a variedade de marcas e modelos de aparelhos disponíveis no mercado. Quem já tentou instalar aplicativos escritos em J2ME no celular já percebeu que a idéia de “write once, run anyhwere” não se aplica muito bem. Para usuários de PC eu já acho que o serviço não deve fazer muito sucesso.

E você, o que acha ?

[]’s

Leonardo X. T. Cardoso

Dados sobre o faturamento anual do Firefox

Sempre me perguntei como a fundação Mozilla que é a responsável pelo desenvolvimento do navegador Firefox se mantinha ativa. Como ela ganhava dinheiro para suportar o desenvolvimento do Firefox ? Apesar de muita coisa ser feita de graça por programadores ao redor do mundo, ela possui alguns funcionários e muitos custos fixos de infraestrutura.
Como pagam isso ?

Hoje encontrei um post que esclareceu parte de minhas dúvidas.

Cerca de 85% do faturamento da fundação Mozilla vem de apenas um acordo feito com o Google que garante a bagatela de aproximadamente 57 milhões de doláres anuais.

Para receber este dinheiro basta que a Mozilla mantenha o Google como site de busca default no Firefox. Este acordo vai ate 2011.

Segundo o CEO da Mozilla John Lilly, este dinheiro é usado para pagar funcionários (que são poucos), despesas de hardware/internet, e para distribuição de prêmios.

Mas e ai ? 57 milhões para cobrir os custos não é muita coisa ?
Clicando neste link podemos ver que a quantidade de funcionários é mínima.
Não estou dizendo que alguem esta ficando rico com o navegador, mas tenho curiosidade em saber mais detalhes sobre a contabilidade da fundação.

Alguem ai tem alguma referência ?

[]'s

segunda-feira, 25 de maio de 2009

Workarounds mais ridiculos para bugs em programas

Ontem o slashdot iniciou uma discussão bem interessante sobre os workarounds mais ridículos propostos para a solução temporária de algum bug.

Dois deles são inacreditáveis:

1. Certa vez a Microsoft instruiu seus usuários a mexer continuamente o mouse por vários minutos para que pudessem visualizar os dados provenientes do Oracle no Excel.

2. Recentemente a HP recebeu diversas reclamações de clientes informando que o Office 2007 não era estável em computadores com impressoras HP instaladas. A solução proposta pela HP a seus clientes foi não deixar impressoras HP como a impressora default do sistema. Isso faria com que o Office 2007 funcionasse sem maiores problemas.

E você ? Conhece algum ?

[]'s

Leonardo X. T. Cardoso

Microsoft vai banir o uso da função memcpy

Ainda este ano, a Microsoft irá adicionar as funções memcpy(), CopyMemory(), e RtlCopyMemory() à lista de funções banidas de seu Ciclo de Desenvolvimento Seguro - SDL.

Desenvolvedores que pretendem estar de acordo com as regras do SDL deverão substituir as chamadas de memcpy() para memcpy_s(), que recebe um parâmetro adicional informando o tamanho do buffer para onde os dados serão copiados.
Isso já acontece com outras funções como strcat() e strcpy() que já possuem suas versões seguras strcat_s() e strcpy_s().

[]'s

Leonardo X. T. Cardoso