logo
Contato | Sobre...        
rebarba rebarba

Rodrigo Strauss :: Blog

follow us in feedly

Talvez você ache interessante ver a lista com todos os posts ou minha lista com os melhores posts.

C++11: Inicialização uniforme

Algumas mudanças no C++11 são tão grandes que têm o potencial de deixar a linguagem muito melhor, porém irreconhecível. Além do recurso de lambda (do que eu já falei) os recursos de inicialização uniforme e nova sintaxe para declaração de funções são desse tipo. Hoje vou falar sobre Uniform Initialization (ou inicialização uniforme em bom português).

O C++ tem a característica de não ser uma linguagem uniforme. Isso quer dizer que uma sequência específica de tokens pode ter significados diferentes dependendo do contexto. Isso causa diversos problemas, entre ele uma dificuldade bem maior para escrever um parser (interpretador) para a linguagem. Veja a seguinte expressão:

  1. MeuObjeto algumaCoisa(10, "lala");

Esse código pode significar duas coisas: uma declaração de função que retorna MeuObjeto ou a declaração de uma varíavel do tipo meu objeto que tem um construtor com dois parâmetros. Isso existe devido à algo que é chamado de Most Vexing Parser, ou Interpretador Mais Vexaminoso na língua de Camões. Nesse caso específico, essa linha será interpretada como uma declaração de função, algo bem inconviniente caso o trecho acima esteja dentro de uma função:

  1. class MeuObjeto
  2. {
  3. public:
  4.   MeuObjeto(int a, string b) {}
  5. };
  6.  
  7. int main()
  8. {
  9.   // Parece algo normal, mas isso é um erro de compilação
  10.   // Isso será interpretado como uma declaração de função
  11.   MeuObjeto algumaCoisa(10, "lala");
  12. }

Para resolver esse problema, entre outros, foi criada a inicialização uniforme:

  1. int main()
  2. {
  3.   // Como usamos colchetes ao invés de parenteses,
  4.   // o compilador sabe com certeza que isso é uma chamada
  5.   // de construtor (e não uma declaração de função)
  6.   MeuObjeto algumaCoisa{10, "lala"};
  7. }

Mas como sempre, a forma anterior de fazer as coisas continua valendo. Lembrem-se: o C++ tem como premissa continuar compatível com todo código fonte que já foi escrito até hoje. Essa é a maldição e a benção do C++: a linguagem evolui e fica competitiva em relação às linguagens mais novas, mas os programadores podem continuar fazendo as coisas da forma antiga e, muitas vezes, pouco recomendáveis. Um exemplo é a parte de gerenciamento de memória. Vou repetir o que digo em quase toda palestra: se você está usando new e delete você está fazendo isso errado.

O recurso de inicialização uniforme permite que toda inicialização de instâncias de objetos e estruturas usem essa nova sintaxe:

  1. // Lembrando que tipos fundamentais também aceitam
  2. // a sintaxe de construtor
  3. int i {3};
  4.  
  5. // Inclusive um construtor vazio (nesse caso i2 == 0)
  6. int i2 {}; // empty braces initialize the object to it's default (0)
  7.  
  8. // a std:string é uma classe, e aceita uma string
  9. // literal no construtor
  10. std::string s {"hello"};
  11.  
  12. MeuObjeto algumaCoisa {10, "lala"};
  13.  
  14. MeuObjeto muitasCoisas[] = { {10, "lala"}, {20, "lili"} };

É uma pequena mudança que resolve grandes problemas.

Em 17/02/2016 06:43 - Comentários (3)

Semântica

É engraçado como a semântica da maioria dos mortais não vale para programação. "Legado" da forma que aprendi na escola é algo bom, que é passado entre as gerações. O dicionário confirma. Mas o significado dessa palavra mudou no decorrer dos anos. Pelo menos para nós, escovadores de bits.

Para quem trabalha com programação, "legado" é aquele código antigo que ninguém quer dar manutenção e que todo mundo culpa por todos os problemas. Problemas em produção? É culpa do código legado. O projeto levou o dobro do tempo? É porque "precisamos contornar o legado". O sistema dá problema em produção todo dia? "É só a parte do legado, o que fizemos no último ano funciona". O sistema e a empresa continua com problemas, mas parece que culpar o legado isenta todo mundo de toda e qualquer responsabilidade.

Então começamos um projeto novo para "resolver o legado", depois de convencer todo mundo. Sempre pensamos que, dessa vez, vamos fazer diferente e montar uma arquitetura que é robusta, escalável e que vai ajudar a empresa a crescer, sem os problemas do passado. Afinal, agora somos mais espertos e entendemos mais sobre programação. Mas isso **nunca** acontece. Por que?

Nós estamos hoje construindo o legado de amanhã. Tanto no bom sentido quanto no mal sentido (mais uma vez me lembro como é engraçado em programação a palavra "legado" ter um conotação ruim por si só). Daqui alguns anos, o código que estamos escrevendo hoje também será um "código legado". E por que isso? Existem vários motivos, o principal é: não conseguimos prever o futuro. Isso simplesmente não é possível. No futuro as necessidades serão outras, as técnicas serão outras, e pricipalmente as pessoas e suas visões de mundo serão outras. Todas as tentativas que eu vi de fazer um sistema que seria genérico o suficiente para prever o futuro acabou gerando um meta framework super genérico que só piorava a situação.

O framework genérico caseiro é um erro clássico de grandes empresas, quase sempre obra dos ditos "Arquitetos de Software". Já vi vários casos onde a empresa faz seu próprio framework e bibliotecas internas para coisas simples como acesso à banco de dados, só para garantir que os programadores vão "fazer a coisa certa". Aí todo mundo passa boa parte do tempo contornando esse framework interno que foi feito por uma "equipe de arquitetura" que não tem programadores ou engenheiros de software experientes. Geralmente as equipes de arquitetura são formadas por pessoas que querem um salário maior e menos pressão por prazo e qualidade. Como um deles já me disse uma vez, "no Word sempre compila, ser arquiteto é bem mais fácil".

E algumas vezes a proposta para "resolver o levado" é jogá-lo fora e recomeçar. **A IDEIA MAIS ESTÚPIDA DO PLANETA**. O Joel já disso isso faz tempo e parece que ninguém entendeu. Você não pega um código fonte que funciona e simplesmente joga fora. Você pode reorganizá-lo e substituir as partes problemáticas aos poucos, mas trocar tudo de uma vez é algo que eu nunca vi funcionar. Nunca.

Software não é algo estático, ele precisa estar sempre em evolução. O legado é eterno. A atenção que damos para ele determina se o legado será bom ou ruim. Ao invés de fazer um projeto novo a cada 4 ou 5 anos, devemos manter o software evoluindo sempre. A Microsoft refaz o Word de tempos em tempos? E o Linux, ele passa por uma reformulação geral a cada 5 anos? Não. Software de qualidade está sempre evoluindo. É assim que deve ser.

Lembre-se: código fonte é código fonte. Bonito ou feio, novo ou velho. E é nossa responsabilidade fazer com que o ele continue funcionando. Então, por favor, deixe de frescura, abra aquele código fonte antigo, entenda como ele funciona e mantenha tudo funcionando e evoluindo. É o seu legado.

Em 19/11/2015 06:56 - Comentários (1)

C++11: Range based for loop

Todos os programadores C++ sabem que para percorrer qualquer tipo de container devemos usar iterators e nunca um índice. Certo? Na dúvida, eu já escrevi uma extensa série sobre STL, e escrevi um post só sobre iterators. Lembre-se que se você usa C++ sem STL você está usando C com classes.

Apesar do acesso via iterator ter inúmeras vantagens, ele requer uma dose grande código repetitivo. E isso é incompatível com o fato de que nós, programadores, somos preguiçosos por natureza. Afinal, muita gente começou a programar para automatizar tarefas repetitivas. Como resolver isso?

Dois iterators definem um range (intervalo em pt-br). Eles delimitam o início desse intervalo, com o primeiro item inclusive e o segundo item exclusive (ou seja, o último item de um range **nunca** é válido e aponta para um item após o último item válido). Todos os algoritmos da STL ou compatíveis com a STL trabalham em cima de um par de iterators que define os itens que serão tratados pelo algoritmo (eu também já escrevi sobre algoritmos)

Para percorrer todos os itens de um container (seja ele um vector ou um unordered_map) usando um for nomal, você precisa percorrê-lo do begin() até o end(). Apesar de os containers da STL não implementarem um interface que obrigue isso - já que a STL não usa polimorfismo e sim programação genérica - existe um concept que define que container.begin() e container.end() precisam retornar iterators para o início e o fim do container. A página da saudosa Silicon Graphics sobre STL tem essas definições bem explicadas e documentadas.

Sabendo disso, esse é o código para percorrer todos os itens de um container:

Repetitivo e verbose, certo? O conceito de iterators foi criado para que você possa aplicar um algoritmo à qualquer intervalo de um container, mas na maioria das vezes você faz isso sobre todos os itens. O range based for é um loop que "extrai" automaticamente o range completo de qualquer coisa que você passar para ele.

Veja como fica o código acima usando range based for:

A partir do C++11 o jeito preferido de pegar os iterators é usando as funções livres begin() e end(). Por que? Porque isso torna o código mais genérico. O vector possui begin() e end(), mas o array C não possui e o container de um framework de terceiros também não. Usando as funções livres permite que você crie especializações delas para containers que não sigam os concepts das STL. Veja isso:

Sim, você entendeu direito. O range based for é só um syntax sugar.

Em 01/10/2015 09:25 - Comentários (0)

Índice para a série de posts sobre o Itanium, por Raymond Chen

O Raymond Chen escreveu uma série sobre o assembly do Itanium. Apesar do Itanium ter sido um fiasco comercial sua arquitetura é genial e a série vale a leitura.

Não tem índice para os tópicos da série no site dele. Então eu batuquei um regex no teclado e fiz um índice.

Parte 1
Parte 2
Parte 3
Parte 3b
Parte 4
Parte 5
Parte 6
Parte 7
Parte 8
Parte 9
Parte 10

Em 25/09/2015 22:37 - Comentários (0)

Sobre a Microsoft e o open source

Muito se tem falado sobre esse novo movimento da Microsoft em direção ao open souce. Para muitos da velha guarda, ver a mesma empresa tida como monopolista dos anos 90 fazendo isso tem gerado muita desconfiança. Como uma empresa de software proprietário vai aderir ao movimento open source?

Sim, a Microsoft aderiu ao modelo de código aberto. Mas as pessoas esqueceram o X da questão: código aberto é diferente de software livre. A governança open source virou algo mais eficiente que a governança fechada. Quanto mais feedback dos usuários, melhor. Quando os usuários são técnicos, como nós programadores, melhor ainda. E como adoramos código fonte, ficamos mais felizes e damos mais feedback. Com podemos ver o código fonte, dizemos onde o erro está e até mandamos a correção pronta. Qual empresa não gostaria que seus clientes e usuários ajudassem a arrumar seu próprio produto?

Inacreditavelmente, hoje em dia muita gente gosta da Microsoft (com a exceção dos fanáticos do free software, é claro). No Hacker News, onde me parece que a maioria do pessoal é de Linux, há um sentimento geral positivo em relação à Microsoft. É irônico ver isso depois de todos esses anos... Levei bastante tempo para entender como a Microsoft funciona e como ela pensa. Já li muita coisa, já assisti muita coisa (como o Channel9) e já visitei a Microsoft em Redmond 2 vezes, uma como representante do grupo C & C++ Brasil e outra como MVP. Minha carreira sempre orbitou em volta de softwares da Microsoft e eu comecei a programar usando um software deles, o GW Basic. Tenho usado bastante Linux ultimamente, mas isso não me afastou do Windows e, principalmente, do Visual Studio.

Apesar de gostar da Microsoft no geral, eu não concordo com tudo que eles fazem. Esse costume horrendo que eles têm de implementar parcialmente os padrões (principalmente os padrão ISO do C++) segundo a visão puramente mercadológica é uma abominação. Eles levaram tempo para entender que implementar o padrão C++ era mais importante do que implementar só a parte que eles usam. Isso só chegou esse ano, para meu total desgosto e desespero. Mas mesmo assim continuei com o Visual C++ por causa da qualidade. Eu já tentei migrar para o GCC. Mas a qualidade do ferramental da Microsoft é muito alta e acabei ficando com o ecosistema do Visual Studio. Apesar do Fora o famigerado C++/CLI...

Mas uma coisa é inegável: a Microsoft é uma máquina extremamente eficiente de fazer software. Eles foram durante muitos anos a única empresa do mundo que sabia fazer software. Todas as empresas que competiram com eles caíram, a Netscape, a Borland, a Word Perfect, a Lotus. E não era por monopólio ou coisas assim, como gostam de dizer. Foi por competência em Engenharia de Software. O Excel venceu o Lotus 1-2-3 porque era melhor. O Word venceu o WordPerfect porque, versão após versão, ficou melhor. E o Internet Explorer ficou melhor que o Netscape.

Eu sei o que você está pensando. Blablaba monopólio blablabla. O IE continua vindo junto com o Windows, e mesmo assim todo mundo baixa o Chrome e o Firefox. Hoje o Internet Explorer é basicamente uma ferramenta gigante que serve para baixar outros browsers. Poderia ter sido assim na época. Mas a Netscape foi estúpida o suficiente para fazer a maior estupidez que uma empresa pode fazer: jogar fora o código fonte porque ele "está feio "e comerçar tudo de novo.

Voltando ao open source. A coisa é simples. Eles estão se adaptando ao mercado, como eles sempre fizeram. A Microsoft nunca foi inovadora, como a Apple ou mesmo o Google. Eles inovaram várias vezes (o Visual Basic foi o precursor de todos as IDEs modernas), mais o foco deles não é a inovação. É fazer software direito. E nisso eles são muito bons, é inegável.

Eles levaram bastante tempo para entrar na Internet, tentando levar as pessoas para a MSN, que era uma rede separada, tipo a Compuserve. Depois foi uma versão do IE atrás da outra e a Netscape morreu pela própria incompetência (novamente, alguém aí usa IE só porque vem junto com o Windows?).

Eles levaram tempo para entrar no mercado de nuvem. Hoje o Azure fatura milhões.

Eles levaram tempo para entender o mercado de mobile. O Windows Phone... é.... mmm... está aí.

E agora eles entenderam o modelo de negócio open source e estão se adaptando. Como sempre fizeram. E garanto que vão fazer isso melhor do que gente que está aí faz tempo, como IBM e outros, pelo simples fato de que eles entendem de software como ninguém. Até onde sei, o modelo aberto do .NET já nasceu mais aberto que o Java...

Em 27/08/2015 08:01 - Comentários (0)


Posts anteriores >>
rebarba rebarba
  ::::