terça-feira, 18 de junho de 2013

Novas Linguagens e Ambientes de Execução

Ultimamente tem sido crescente a discussão sobre JavaScript e linguagens que "compilam" para JavaScript, como CoffeeScript, TypeScript e outras. Já testei algumas dessas linguagens e todas elas, na minha opinião, são incrivelmente superiores em muitos aspectos ao JavaScript.

Outra questão que vejo ser abordada com frequência recentemente é o uso de Node.js, um framework realmente fantástico, performático, incrivelmente escalável e totalmente assíncrono. Mas que no entanto só entende uma linguagem: JavaScript. Obviamente as linguagens que compilam para JavaScript podem ser usadas ao se trabalhar com Node.js, mas nativamente não são suportadas, ainda.

Outro ambiente de execução que tem sido muito bem avaliado é a máquina virtual Erlang. No entanto, a linguagem Erlang em si é monstruosamente horrorosa e até o momento a melhor tentativa de ser executar uma outra linguagem sobre essa máquina virtual tem sido a Elixir.

No caso da gigante JVM, já faz algum tempo que a comunidade Java começou a admitir que a linguagem Java é uma linguagem verbosa demais, improdutiva e deficiente em muitos aspectos. Como resposta a isso surgiram Scala, Groove, Clojure, Kotlin. Todas essas, linguagens que são executadas sobre a JVM, trazendo muitas vantagens quando comparadas com sua matriarca, Java. 

No mundo .NET, diversas linguagens em um único ambiente de execução já é algo que existe desde sua concepção e com certeza parte da inspiração para a criação de novas linguagens executando sobre a JVM e compilando para JavaScript vieram dai.

A competição, a necessidade e principalmente a insatisfação tem levado ao surgimento de ao menos uma nova linguagem a cada ano, no entanto falta a essas linguagens, e principalmente a suas máquinas virtuais, a visão de que para ganhar mercado, a linguagem não precisa ser apenas universal e performática, precisa também ser produtiva, agradável de se usar.

Imaginem poder executar CoffeeScript diretamente sobre o Node.js ou nos navegadores web, ou código Ruby ou C# sobre a máquina virtual Erlang. Certamente o crescimento e a popularidade desses ambientes cresceria bastante.

Isso me lembra o projeto Singularity, mas isso fica para um próximo post.

segunda-feira, 3 de junho de 2013

C#, Java e os Enums - Parte 3

No último post apresentei a implementação Java do State OnOff, usando os Enums do Java 1.5.

Abaixo você pode ver a minha implementação para o padrão State em C#, seguindo o mesmo modelo visto na versão Java.
public abstract partial class OnOff {
    public partial class OnState : OnOff {
        public override string DisplayText {
            get { return "Ligado"; }
        }

        public override OnOff Switch() {
            return OnOff.Off;
        }
    }

    public partial class OffState : OnOff {
        public override string DisplayText {
            get { return "Desligado"; }
        }

        public override OnOff Switch() {
            return OnOff.On;
        }
    }

    public abstract OnOff Switch();
    public abstract string DisplayText { get; }
}
Fiquei surpreso em ter conseguido um código aparentemente tão enxuto e tão próximo da versão Java, no entanto o código acima não está completo. Note o uso do modificador partial na declaração das classes e o uso dos valores OnOff.On e OnOff.Off nas implementações do método Switch. A implementação desses dois valores, que são propriedades estáticas da classe OnOff, foi feita em um arquivo separado, como outra parte da classe OnOff, juntamente com muitos outros truques necessários para tornar esse State quase tão simples de se usar quanto a versão Java, provendo ainda alguns recursos extras bem interessantes.

É fácil notar também que não basta declarar as classes OnState e OffState. Como os valores que essas classes representam são de fato disponibilizados e utilizados?

Neste repositório do GitHub você encontra a versão completa dessa implementação e poderá ver com detalhes como foi implementada essa segunda parte da classe, disponível no arquivo OnOff.Partials.Boilerplate.cs. Note também que há uma classe base genérica denominada State<TState, TValues>, que utilizei para encapsular mais código boilerplate necessário para a implementação.

Com tanto código boilerplate para um exemplo tão simples, essa implementação poderia ser considerada inviável, ou no mínimo muito pouco prática, ainda que um gerador de código possa ser implementado para reconstruir o arquivo .Boilerplate.cs a cada vez que o State for alterado.

Ainda assim achei as opções disponíveis para a implementação bastante interessantes e gostei do exercício.

Não quero fazer disso aqui um manual completo de como usar minha implementação, quero apenas apresentá-la. Se tiver se interessado navegue pelo código no GitHub e acredito que encontrará algumas construções bem interessantes.

Encerro com alguns exemplos de uso desse State :

Uso dos valores On e Off:
[Test]
public void TestOnOffSwitches() {
    OnOff on = OnOff.On;
    OnOff off = OnOff.Off;

    OnOff onSwitched = on.Switch();
    OnOff offSwitched = off.Switch();

    Assert.AreEqual(on, offSwitched);
    Assert.AreEqual(off, onSwitched);
}
Uso do State em um bloco Switch:
[Test]
public void TestSwitchStatement() {
    OnOff on = OnOff.On;
    switch (on.Value){
        case OnOff.Values.On:
            break;
        default:
            Assert.Fail();
            break;
    }
    OnOff off = OnOff.Off;
    switch (off.Value) {
        case OnOff.Values.Off:
            break;
        default:
            Assert.Fail();
            break;
    }
}
Conversão do valor do State para um byte:
[Test]
public void TestCastValueToByte()
{
    byte onValueAsByte = (byte)OnOff.On.Value;
    OnOff.Values onValue = (OnOff.Values)onValueAsByte;
    Assert.AreEqual(OnOff.On.Value, onValue);
}
Enumeração dos valores disponíveis para o State:
[Test]
public void TestStates()
{
    IEnumerable<OnOff> states = OnOff.States;
    Assert.NotNull(states);

    OnOff statesOn = states.SingleOrDefault(s => s == OnOff.On);
    Assert.AreEqual(statesOn, OnOff.On);

    OnOff statesOff = states.SingleOrDefault(s => s == OnOff.Off);
    Assert.AreEqual(statesOff, OnOff.Off);
}