Mostrando postagens com marcador orientação a objetos. Mostrar todas as postagens
Mostrando postagens com marcador orientação a objetos. Mostrar todas as postagens

20 de out. de 2011

Todo mundo quer uma API extensível

Como programador Java mas entusiasta de novas linguagens, acabo por sentir falta de alguns recursos que facilitam muito o trabalho, ou que pelo menos para mim fazem mais sentido usar.

Posso começar com um estudo de caso simples: dada uma String retornar o número de palavras.

É assim mesmo, simples assim, inclusive muito fácil de implementar em qualquer linguagem, mas a questão não é essa, como desenvolvedor eu quero usar orientação a objetos no projeto.

Vamos a uma implementação tosca em Java:
String frase = "Uma frase  de   exemplo";
System.out.println(frase.trim().split("\\s+").length);
Deu. Mostra 4. Entretanto eu quero reutilizar esta funcionalidade então em componentizo, bem, mas como?

Posso usar outro estudo de caso para dramatizar mais a história: verificar se uma String está em branco, ou seja, semelhante ao vazio só que ignorando espaços.

A implementação é medíocre:
String texto = "    ";
if (texto.trim().length() == 0) {
    System.out.println("vazio");
}
Não obstante, como no primeiro caso, eu quero componentizar.

No Java, é clássico fazer uma classe utilitária, algo como TipoUtils, neste caso, StringUtils:
public class StringUtils {
    public static int words(String str) {
        return str.trim().split("\\s+").length;
    }

    public static boolean isBlank(String str) {
        return str.trim().length() == 0;
    }
}
E uso assim:
String texto = "    ";
if (StringUtils.isBlank(texto)) {
    System.out.println("vazio");
}
Ainda posso usar um recurso introduzido no Java 5, o import estático.
import static meu.framework.utils.StringUtils.*;
// algumas linhas abaixo
String texto = "    ";
if (isBlank(texto)) {
    System.out.println("vazio");
}
Qual o problema com esta implementação? É que ela soa totalmente procedural em contraste ao modelo OO escolhido, em outras palavras eu queria fazer isso:
String texto = "    ";
// quero o próprio objeto me diga se está em branco
if (texto.isBlank()) {
    System.out.println("vazio");
} else {
     // quero que o próprio objeto me diga quantas palavras tem
    System.out.println("Existem " + texto.words() + " palavra(s)");
}
Em Java, impossível. No Java a classe String é final, ou seja, não pode ser estendida.

Para constar, uma extensão da API base do Java já existe e é distribuída pelo projeto commons do Apache e uma classe StringUtils já existe para estender as funcionalidades relacionadas a Strings e é muito bem escrita.

Mas isso não me deixa contente por que outras linguagens lidam muito melhor com esta situação, dando melhor suporte para estender a API base.

Vamos ao mesmo exemplo usando C#. No C# é possível, de certo modo, estender qualquer classe, mesmo as finais (sealed em C#), usando somente a API pública da classe, que já é suficiente para realizar muitas proezas:
public static class StringUtils {
 public static int Words(this string str) {
  return Regex.Split(str.Trim(), "\\s+").Length;
 }
 public static bool IsBlank(this string str) {
  return str.Trim().Length == 0;
 }
}
Implementações de classes estáticas no C# permitem estender a funcionalidade qualquer classe. Na verdade é um açúcar sintático no qual ele passa o conteúdo da variável para o método estático, ainda sendo procedural, mas de melhor leitura e mais elegante que em Java. Eu posso chamá-lo assim:
string texto = "    ";
if (texto.IsBlank()) {
    Console.WriteLine("vazio");
} else {
    Console.WriteLine("Existem " + texto.Words() + " palavra(s)");
}
Bem mais OO não acha? Pode ficar ainda melhor em Ruby, onde as classes são abertas. Em outras palavras, é possível estender a funcionalidade até mesmo das classes básicas como String e FixNum (inteiros). Claro que esta liberdade deve ser usada com parcimônia, é bem mais fácil fazer caca, mas com responsabilidade dá para fazer isso:
class String
    def words
        self.split.length
    end
    def blank?
        self.strip.length == 0
    end
end
Então eu posso usar estes métodos assim:
texto = "uma frase"
print texto.words
print "vazio" if texto.blank?
Sinceramente, sinto falta dessa flexibilidade em Java.

Acho exagerado a recomendação do Pragmatic Programmers de que todo programador deveria aprender uma linguagem por ano, por outro lado entendo o motivo que é propiciar novas visões, pontos de vista, ser mais crítico ao seu código, saber que há alternativas para fazer, melhor ou pior, aquilo que tu já faz todo o dia.

9 de fev. de 2011

Paradigmas, Coleções, Java, Programação Funcional, C# e Ruby

São vários os paradigmas de programação, entretanto os mais conhecidos e abordados são imperativo, estruturado, procedural e orientado a objetos (OOP). Os quais são suportados por muitas linguagens conhecidas como PHP, Java, Visual Basic, etc. Outros que tem destaque no desenvolvimento de aplicações são o funcional e orientado a aspectos (AOP).

Vou usar um estudo de caso simples nesse post para contrastar:
Imagine uma coleção de candidatos, com apenas dois atributos: nome e idade. Após obter esta lista, de um base de dados ou integração, é necessário subdividi-la em duas: candidatos maiores de idade e menores de idade. Preferencialmente deve ser uma solução reusável.

Abaixo fiz uma implementação em Java. Existem várias estratégias de implementação para obter os menores e maiores, qual seria a sua?

Arquivo Main.java
import java.util.*;

public class Main {

 public static void main(String[] args) {
  
  List<Candidato> candidatos = getCandidatosFromDataSource();
  
  //List<Candidato> menores = ??;
  //List<Candidato> maiores = ??;
  
 }
 
 
 public static List<Candidato> getCandidatosFromDataSource() {
  List<Candidato> candidatos = new ArrayList<Candidato>();
  
  candidatos.add(new Candidato("Alvaro", 23));
  candidatos.add(new Candidato("Vanessa", 13));
  candidatos.add(new Candidato("Paulo", 54));
  candidatos.add(new Candidato("André", 17));
  candidatos.add(new Candidato("Renata", 32));
  
  return candidatos;
 }
  
}

class Candidato {
 
 public String nome;
 
 public int idade; 
 
 public Candidato(String nome, int idade) {
  this.nome = nome; this.idade = idade;
 }

 @Override
 public String toString() {
  return "Candidato [nome=" + nome + ", idade=" + idade + "]";
 }
 
}



Para ilustrar vou extrair os menores de idade com algumas estratégias em Java e depois usando paradigma funcional em C#.


Java - exemplo 1 - usando lista temporária para adicionar os candidatos que aderem a regra:

public static void main(String[] args) {
 
 List<Candidato> candidatos = getCandidatosFromDataSource();
 
 List<Candidato> menores = menoresDeIdade(candidatos);  
 
 System.out.println(menores);
 
}

public static List<Candidato> menoresDeIdade(List<Candidato> candidatos) {
 List<Candidato> menores = new ArrayList<Candidato>();
 for (Candidato c : candidatos) 
  if (c.idade < 18)
   menores.add(c);
 return menores;
}

Este método funciona normalmente como uma implementação procedural. Java - exemplo 2 - usando lista temporária para remover os candidatos que não aderem a regra:

public static void main(String[] args) {
 
 List<Candidato> candidatos = getCandidatosFromDataSource();
 
 List<Candidato> menores = menoresDeIdade(candidatos);  
 
 System.out.println(menores);
 
}

public static List<Candidato> menoresDeIdade(List<Candidato> candidatos) {
 List<Candidato> menores = new ArrayList<Candidato>(candidatos);
 for (Candidato c : menores)
  if (c.idade > 18) menores.remove(c);
 return menores;
}

Esse método FALHA. Não é possível iterar e manipular uma lista simultaneamente. A seguinte exceção será lançada: Exception in thread "main" java.util.ConcurrentModificationException Na verdade, esse é um erro bem comum de programadores Java que não conhecem a API Collections. O método acima funciona se tu usares um ListIterator, que permite percorrer e manipular a lista. Exemplo corrigido:

public static List<Candidato> menoresDeIdade(List<Candidato> candidatos) {
 List<Candidato> menores = new ArrayList<Candidato>(candidatos);
 ListIterator<Candidato> iCandidato = menores.listIterator();
 while (iCandidato.hasNext()) {
  Candidato c = iCandidato.next();
  if (c.idade > 18) 
   iCandidato.remove();
 }  
 return menores;
}

Ok? Dúvidas, comentem.

 Java - exemplo 3 - especializando a coleção de Candidatos:

public static void main(String[] args) {
  
 Candidatos candidatos = new Candidatos(getCandidatosFromDataSource());
 
 System.out.println(candidatos.menoresDeIdade());
 
}


class Candidatos extends ArrayList<Candidato> {
 private static final long serialVersionUID = 0;

 public Candidatos() {
  super();
 }
 
 public Candidatos(Collection c) {
  super(c);
 }
  
 public Candidatos menoresDeIdade() {
  Candidatos menores = new Candidatos();
  for (Candidato c : this) 
   if (c.idade < 18)
    menores.add(c);
  return menores;
 }
}


Particularmente, acho essa solução mais elegante. Ela é orientada a objetos, bem diferente das outras, que chamavam um procedimento passando a lista de Candidatos (procedural). Alguns não gostam por que tem que criar classes, mas o que faz o programador de linguagens orientada a objetos senão modelar e criar classes?

 Dica: Não tenha medo de criar classes.

 O modo C# de fazer 

Assim como em outras linguagens, existem várias estratégias possíveis para fazer esta implementação. Os métodos utilizados em Java também podem ser usados em C#, mas existem duas formas particulares de fazer. Os exemplos a seguir são baseados no código abaixo: 

Arquivo Program.cs

using System;
using System.Collections.Generic;

class Program {

    static void Main(string[] args) {

        List<Candidato> candidatos = getCandidatosFromDataSource();

        // List<Candidato> menores = ??

    }

    public static List<Candidato> getCandidatosFromDataSource() {
        List<Candidato> Candidatos = new List<Candidato>();

        Candidatos.Add(new Candidato { Nome = "Alvaro", Idade = 23 });
        Candidatos.Add(new Candidato { Nome = "Vanessa", Idade = 13 });
        Candidatos.Add(new Candidato { Nome = "Paulo", Idade = 54 });
        Candidatos.Add(new Candidato { Nome = "André", Idade = 17 });
        Candidatos.Add(new Candidato { Nome = "Renata", Idade = 32 });

        return Candidatos;
    }

}

class Candidato {
    public string Nome { get; set; }
    public int Idade { get; set; }

    public override string ToString() {
        return "Candidato[Nome: " + Nome + ", Idade: " + Idade + "]";
    }
}

C# - exemplo 1 - usando yeld:

static void Main(string[] args) {

    List<Candidato> candidatos = getCandidatosFromDataSource();

    foreach(Candidato c in Menor(candidatos))
        Console.WriteLine(c);

}

public static IEnumerable<Candidato> Menor (List<Candidato> Candidatos) {
    foreach (Candidato p in Candidatos)
        if (p.Idade < 18) 
            yield return p;
}

Usando yeld return, é possível acumular os objetos em um IEnumerable, que mais tarde pode ser iterado exatamente como no exemplo.


C# - exemplo 2 - usando extension method, delegate e lambda: 

Tudo começa com esta classe de extensão:

static class Util {

    public static List<Candidato> SomenteSe(this List<Candidato> lista, Criterio crit) {
        List<Candidato> candidatos = new List<Candidato>();
        foreach (Candidato c in lista)
            if (crit(c)) 
                candidatos.Add(c);
        return candidatos;
    }

    public delegate bool Criterio(Candidato c);

}

Com ela posso retornar qualquer sublista de acordo com um Criterio, a definir. Melhor com um exemplo de uso:

static void Main(string[] args) {

    List<Candidato> candidatos = getCandidatosFromDataSource();

    foreach (Candidato c in candidatos.SomenteSe(c => c.Idade < 18))
        Console.WriteLine(c);

}

Neste exemplo o método SomenteSe é uma extensão de List<Candidato>. O parâmetro no parenteses é uma expressão lambda que representa o delegado que avalia o Criterio. É lida mais ou menos assim: para cada candidato c retorna verdadeiro se c.Idade for menor que 18. Essa é uma abordagem funcional, pois eu delego parte do processamento para uma função. 
<Candidato>

<Candidato> Na prática eu nem precisaria ter implementado por que o C# já tem uma API para lidar com coleções chamada LINQ. 
<Candidato>

<Candidato> C# - exemplo 3 - usando o LINQ: 
<Candidato>

 LINQ é o acrônimo de Language Integrated Query. O LINQ é usado para manipular coleções com vários tipos de implementações como: LINQ to Objects, LINQ to XML, LINQ to DataSet, LINQ to SQL, LINQ to Entities, e por aí vai. Cada biblioteca abstrai a manipulação de objetos, elementos ou nodos.

Para usar o LINQ para objetos é necessário declarar o namespace: using System.Linq;

A implementação fica assim:

static void Main(string[] args) {
    
    List<Candidato> candidatos = getCandidatosFromDataSource();

    foreach (Candidato c in candidatos.Where(c => c.Idade < 18))
        Console.WriteLine(c);

}


Se o critério será usado mais de uma vez basta declará-lo:


static void Main(string[] args) {
    
    List<Candidato> candidatos = getCandidatosFromDataSource();
    
    Func<Candidato, bool=""> menores = c => c.Idade < 18;
    
    foreach (Candidato c in candidatos.Where(menores))
        Console.WriteLine(c);

}


Outras linguagens 

 Só para constar, existem outras linguagens que usam o paradigma funcional como Ruby por exemplo. Para ilustrar colei abaixo a mesma funcionalidade feita com Ruby:

Arquivo candidatos.rb

def main
    candidatos = candidatos_from_data_source

    menores = candidatos.select { |c| c.idade < 18 }
    
    puts menores
end

def candidatos_from_data_source
    candidatos = [
        Candidato.new("Alvaro", 23),
        Candidato.new("Vanessa", 13),
        Candidato.new("Paulo", 54),
        Candidato.new("André", 17),
        Candidato.new("Renata", 32)
    ]
    candidatos
end

class Candidato

    attr_accessor :nome, :idade
    
    def initialize nome, idade
        @nome = nome
        @idade = idade
    end
    
    def to_s
        "Candidato[nome: #{@nome}, idade: #{@idade}]"
    end

end

main


Não é a toa que há demanda por programadores multiparadigma. Ainda conversava com o Leonardo esses dias sobre uma vaga em que pediam conhecimento de Haskell, que é uma linguagem puramente funcional. Posso falar mais em outro post/tópico, inclusive sobre Programação Orientada a Aspectos.

Qualquer dúvida, comentem.

1 de fev. de 2011

Strings no Java


Aproveitando a conversa com o Bruno sobre equals e == queria expor uma situação interessante. O modo como o Java lida com Strings tem sua particularidades que estão diretamente ligadas ao gerenciamento de memória. Por exemplo, no caso abaixo, a primeira assertiva é verdadeira, já que "aaa" é igual a "aaa", e a segunda assertiva é falsa, mesmo digitando "aaa" em "Outro texto". Se o operador == for substituído pelo método equals ambas assertivas retornam verdadeiro. Por quê?

public class Main {
    public static void main(String[] args) {

        String texto = "aaa";

        System.out.println("texto == aaa: " + (texto == "aaa") );

        System.out.print("Outro texto: ");

        String outroTexto = new Scanner(System.in).nextLine();

        System.out.println("texto == outroTexto: " + (texto == outroTexto) );

    }
}


O segredo está na arquitetura da memória no Java, embora existam algumas estratégias diferentes dependendo da implementação da máquina virtual, como a Java Hotspot, Oracle JRockit e o Apache Harmony.

Basicamente temos a memória divida como ...

  • ... uma pequena área chamada Stack (pilha), onde ficam as variáveis locais e chamadas de métodos (onde são empilhados). Por isso quando fazemos um encadeamento muito longo de chamadas, ou um processamento recursivo muito profundo, recebemos o erro: StackOverflowError. O Bruno teve um erro assim no C#;
  • ... um espaço maior, que é a memória disponível para os objetos, chamada Heap. Geralmente o Heap é divido em Young e Tenured (ver imagem abaixo), ou seja, objetos jovens ficam em parte de memória e se sobrevirem ao coletor de lixo são movidos para maduros (tenured), onde o intervalo de tempo para coleta é maior.
  • ... um espaço chamado Permanent Generation (geração permanente), onde ficam as informações carregadas que serão usadas durante todo o tempo de vida da aplicação, desde aberta até fechada. Nesta área ficam as classes por exemplo e outros dados estáticos, e também, e aí está o segredo, as String literais.


Toda String literal no programa, como o "aaa" no código, são instanciadas (new) e armazenadas no PermGen (não no Heap). Assim, quando novamente usamos "aaa", literalmente no código, ele utiliza aquela instância no PermGen. Isto é uma técnica para melhorar a performance e economizar memória, e foi por esse motivo que comparando "aaa" == "aaa" devolve verdadeiro, pois ambos apontam para a mesma String na memória. Agora no caso de usar new String("aaa") (como observou o Paulo), ou ler uma String de uma base de dados, console, parâmetro de uma requisição HTTP, enfim, tudo que não for literal, nós temos uma nova instância.

O resumo da ópera é, como disse o Leonardo, devemos usar o equals, que é implementado para comparar os atributos e não a posição na memória. No C#, é possível usar o operador == sempre, por que ele é sobrescrito na classe String para executar o método equals, ou seja, quando eu faço no C# "aaa" == "aaa", ele faz "aaa".equals("aaa").

Só mais um detalhe, se alguém aqui cria aplicações Web no Java e levanta no Tomcat, Glassfish, JBoss ou Jetty, já deve ter percebido que em desenvolvimento se for fazendo vários deploys, uma hora ou outra, tem que para o servidor e iniciar outra vez por que dá OutOfMemoryError: PermGen space. É por quê cada vez que a aplicação é implantada (deployada é horrível), as classes e Strings literais são novamente colocadas no PermGen e ele acaba estourando.

Algumas leituras sugeridas são:

The Structure of the Java Virtual Machine: http://java.sun.com/docs/books/jvms/second_edition/html/Overview.doc.html

Java HotSpot VM Options: http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html

Entendendo o NoSuchMethodError e o ClassLoader hell: http://www.arquiteturajava.com.br/livro/entendendo-nosuchmethoderror-e-classloader-hell.pdf

Começando com parâmetros e configurações da JVM: http://blog.caelum.com.br/comecando-com-parametros-e-configuracoes-da-jvm/

Mão sei se me fiz entender. Já passei por alguns problemas de performance e estabilidade com Java, por isso conheço um pouco dessa arquitetura.

Abraço a todos

20 de jan. de 2011

C# Extension Methods (e outros temas tranversais)

O problema

Quem aqui né amigo, não precisou de uma funcionalidade em um tipo básico e como não tinha acabou por criar classes com nome -tipo-Util.

Não entendeu? Bem, vou dar um exemplo. Imagine que no Java eu queira saber se uma String é um número (algo que seria útil no recebimento de parâmetros em requisições Web -que são todos string).

Não existe o método isNumber, isInteger, etc, em String. Existem métodos estáticos em Character, como isDigit.

Então, lá vem os TipoUtil's. Exemplo:

public class Main {
    public static void main(String[] args) {
        
        String parametro = "15.2";
        
        System.out.println(StringUtil.isInteger(parametro));    
    }
}

class StringUtil {
    
    public static boolean isInteger(String string) {        
        for (char c : string.toCharArray())
            if ( ! Character.isDigit(c)) return false;
        
        return true;        
    }
    
}

Neste caso, mostra: false.

Obs.: o método poderia ter sido implementado com expressões regulares.
Obs2.: Existem implementações de bibliotecas utilitárias por vários frameworks, como o Apache: http://commons.apache.org/lang/api-2.5/org/apache/commons/lang/StringUtils.html

E se eu chamar:
if ("641".isInteger()) System.out.println("É um Inteiro");

Não, embora pareça legível, não dá. Eu tenho que usar o método estático:
if (StringUtil.isInteger("641")) System.out.println("É um Inteiro");


Procedural vs Orientado a Objetos

Métodos Estáticos são implementações procedurais -sim, é possível programar proceduralmente em uma linguagem orientada a objetos.

O que denuncia isto é a passagem de um objeto para outro, o qual te dá informações sobre o primeiro. Em outras palavras, não é o próprio objeto que sabe de seu estado, eu tenho que passá-lo a outro para obter informações.

Algumas linguagens, mesmo adicionando orientação a objetos, tem aspectos procedurais. Por exemplo, não sei muito de PHP, mas pelo que conheço para saber o tamanho de um array devo chamar a função count (ou seu alias sizeof- corrijam-me se eu estiver errado):



Poderia ser assim:
echo $frutas.count(); // mas não é

Bem, o C#, assim como o Java, é uma linguagem com chamadas estáticas -o próprio Main é um caso. A implementação do isInteger, como foi feito no Java, a princípio não ficaria muito diferente, veja abaixo:

using System;

class Program {
    static void Main(string[] args) {

        string parametro = "123";
        Console.WriteLine(StringUtil.IsInteger(parametro));

    }
}

class StringUtil {
    public static bool IsInteger(string str) {
        foreach (char c in str.ToCharArray())
            if ( ! Char.IsDigit(c)) return false;
            return true;
    }
}

Quase a mesma coisa não é mesmo?

Então como alterar a classe String para que eu possa fazer "123".IsInteger()? Não tem jeito, a classe String é selada (sealed), ou seja, não é possível estendê-la.



Extension Methods

Entretanto, há um subterfúgio que pode deixar o código "menos feio", os Extension Methods, ou métodos de Extensão.

Exemplo:

using System;

class Program {
    static void Main(string[] args) {

        string parametro = "123";
        Console.WriteLine(parametro.IsInteger());

    }
}

static class StringUtil {
    public static bool IsInteger(this string str) {
        foreach (char c in str.ToCharArray())
            if ( ! Char.IsDigit(c)) return false;

        return true;
    }
}

É necessário adicionar a palavra-chave static na classe (uma classe estática só pode ter métodos estáticos) e a palavra-chave this no parâmetro.

Na prática, é um açúcar sintático, se por exemplo eu chamar: "9971".IsInteger()
O Runtime traduz para StringUtil.IsInteger("9971").

Legal, não? Existem várias implementações que são feitas com Extension Methods, inclusive nos Frameworks ORM da Microsoft, o Entity Framework ou o Linq to SQL.

Obs.: Algumas linguagens permitem que eu reabra qualquer tipo, mesmo os internos, como no Ruby. No Ruby eu posso adicionar qualquer método a qualquer classe em tempo de execução, como por exemplo um método para testar se é inteiro "123123".is_integer?. Abaixo a implementação usando o IRB:

class String
     def is_integer?
         self.to_i.to_s == self
     end
end

"23123".is_integer?
# devolve true
"231.23".is_integer?
# devolve false

Obs.: Na convenção de nomes do Ruby, métodos que retornam booleano terminam com ? (interrogação)


Cultura

Quando tu conheces mais de uma linguagem isto ajuda a mudar a visão, uma mudança de cultura. Por exemplo, em C# e Java, para transformar uma string em inteiro, normalmente chamamos um método estático (procedural) da classe Int32/Integer, como no exemplo:

C#:
int valor = int.Parse("12");

Java:
int valor = Integer.parseInt("12");

No Ruby, por exemplo, o método para converter uma string em inteiro está na própria classe string, exemplo:
"12".to_i

Então, como eu gosto dessa "forma" do Ruby, eu implemento em C# assim nos meus projetos:

public static class StringUtils {

    public static int ToInteger(this string text) {
        int number;
        return int.TryParse(text, out number) ? number : 0;
    }

}

Então eu posso fazer isso em C#:
"12".ToInteger();


Design com Exceções ou Não

Optei por fazer um design sem exceções, ou seja, se eu chamar "dsd".ToInteger() retorna 0. Se na implementação eu tivesse usado int.Parse poderia lançar uma exceção se a string não for válida.

O desenvolvedor sempre pode optar pode fazer o design de funcionalidades para exceção ou não, desde que seja elegante e de acordo com o contexto.

Por exemplo, em um sistema Web, se por exemplo for passado na URL o parâmetro domino/produtos?page=12, e a listagem tiver apenas 10 páginas, o que fazer? Mostrar uma tela de página inválida? Ou mostrar a última página (no caso 10)? Particularmente eu optaria por mostrar a última, e se a página fosse inválida (algo como page=dsfsd) eu mostraria a primeira.

Outro exemplo, se recebo na URL domino/cliente/action=excluir?id=200. O ID não existe, o que fazer? Eliminar o último ID? hehehehe, penso que não, este é um bom exemplo de lançar a exceção.

Cada caso é um caso. Não sei se me fiz entender.



Programação Funcional

O C# tem suporte ao paradigma de programação funcional. Ainda não abordei detalhes a respeito, mas adianto que é muito comum usar extension methods e delegados (ou lambdas).

Por exemplo, supondo que com frequência eu tenha que executar alguma tarefas certo número (finito) de vezes. Normalmente usamos um for com um contador, tipo, i = 0 e i < 20, certo? Bem, então eu posso criar um aspecto funcional, usando Extension Methods e Delegates (delegados) para fazer esse processamento, como no código abaixo:

public static class IntegerUtils {

    public delegate void Proc(int value);

    public static void Times(this int value, Proc proc) {
        for (int i = 0; i < value; i++) proc(i + 1);
    }
}

Para usar, um exemplo:
5.Times(delegate (int i) { Console.WriteLine("Iteração " + i); });

Ou, usando uma lambda:
5.Times(i => Console.WriteLine("Iteração " + i));


Obs.: O Ruby também tem suporte a programação funcional através de blocos e procs. Esta implementação que fiz no C# existe no Ruby e poderia ser feito assim:
5.times { |n| puts "Iteração #{n}" }


Acho que é isso. Se alguém testar e tiver algum erro poste aí, fiz os exemplo na correria.

Abraço a todos