Você está na página 1de 77

Explorando C#

Csar Roberto de Souza Rafael Loosli Dias

Resumo anterior...

Orientada a Objetos

Todos elementos do sistema de tipos derivam de Object:

Tipos primitivos (int, double, float) Enumeraes, structs, unions Funes (Delegates, Lambdas)

Orientada a Componentes

Propriedades, mtodos e eventos inerentes a linguagem

Distino entre mtodos e propriedades (ex: getBla vs Bla)

Explorando C#

Programao Genrica Mtodos de Extenso Extenses Funcionais Programao No-segura Compilao

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Explorando C#

Programao Genrica (Generics) Mtodos de Extenso (Extension Methods) Extenses Funcionais (Delegates, Lambda Expressions) Programao No-segura (Cdigo Unsafe) Compilao (JIT e Cdigo Nativo)

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Explorando C#

Programao Genrica (Generics) Mtodos de Extenso (Extension Methods) Extenses Funcionais (Delegates, Lambda Expressions) Programao No-segura (Cdigo Unsafe) Compilao (JIT e Cdigo Nativo)

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Programao Genrica

Diferentes abordagens

Templates (C++) Type erasure (Java) Reification (C#)

Programao Genrica

Templates (C++)

Expandidos durante tempo de compilao

Verso aperfeioada e type-safe de macros em C

Cdigo template sempre necessrio durante a compilao

O cdigo fonte precisa estar sempre disponvel, ou o compilador no poder realizar a expanso. Templates em si no podem ser compilados e distribudos em forma binria (como em uma .dll)

Cada permutao de argumentos template utilizados no corpo do programa gera uma nova expanso (instanciao)

Possibilita usos interessantes como template meta-programming.

Melhor performance possvel todo cdigo resolvido em tempo de compilao

Programao Genrica

Type erasure (Java)

Informaes sobre tipos so apagadas, e internamente, compilam para tipo Object (ou para o tipo mais prximo caso haja restries nos tipos aceitos pela classe) e casts de runtime so introduzidos quando necessrio No aceita tipos primitivos (por compilar para Object - ou tipo mais alto na hierarquia de objetos definida pelas restries) No possvel ter uma classe Foo<T> e Foo num mesmo pacote (por compilarem para o mesmo raw type), nem mtodos com assinatura diferindo apenas pelo argumento template Sem ganhos em performance,

Possivelmente depende de otimizaes do interpretador/compilador JIT para que as coeres de tipo no degradem severamente a performance

Programao Genrica

Type erasure (Java)


public class List<E> { public void add(E Item) { // ... }
public E get(int index) { // ... } } } Compilam para a mesma representao interna (bytecode)

public class List { public void add(Object Item) { // ... }


public Object get(int index) { // ... }

Programao Genrica

Type erasure (Java)


List lista = new List(); // coero implcita para Object lista.Add("teste");

List<String> lista = new List<String>();

lista.Add("teste"); // coero de Object para String String str = (String)lista.get(0); String str = lista.get(0);

Compilam para a mesma representao interna (bytecode)

Programao Genrica

Reification (C#)

Suporte a generics desde a Intermediate Language (IL) Classes compiladas em IL mantm todas informaes sobre seus tipos genricos, incluindo restries IL compilada de maneira similar a templates em C++ Cada especializao de tipo genrico compilada em separado pelo JIT em cdigo nativo durante primeiro encontro

Como um compilador C++, porm durante runtime

Ganho em performance:

No so necessrios casts durante a execuo. Cerca de 100% a 200% de ganho em relao a utilizao de casts.

Programao Genrica
.class public auto ansi beforefieldinit

public class List<T> { public void Add(T Item) { // ... } }

List`1<T> extends object


{ .method public hidebysig instance void Add ( !T Item ) cil managed { .maxstack 8 IL_0000: nop IL_0001: ret

Compilao
}

Programao Genrica
List<double> List<int> List<Decimal> List<StringBuilder >

Cdigo especfico para lista de inteiros

Cdigo especfico para lista de doubles

Cdigo especfico para lista de decimal

Cdigo especfico para lista de ponteiros

Value Types

Reference Types

Application Domain

Programao Genrica

Sintaxe
public interface IEnumerable<T> { // ... }
public static T[] Combine<T>(T[] a, T[] b) { // ... }

public class List<T> { public void Add(T item) { // ... } }

interface IEnumerable<T> where T : ArrayList { // ... }

Programao Genrica

Sintaxe

Constraints
Constraint Explanation type parameter must be a value type type parameter must be a reference type type parameter must have a constructor with no parameters (must appear last) type parameter must inherit from <base_class>

where T : struct where T : class where T : new() where T : <base_class> where T : <interface> where T : U

type parameter must be, or must implement this interface


naked type parameter constraint

Programao Genrica

Exemplos

public class MyList<TKey, TValue> { Node<TKey, TValue> head; public TValue Find(TKey key) { Node<TKey, TValue> current = head; while (current.NextNode != null) { if (current.Key == key) return current.Item; else current = current.NextNode; } throw new Exception("Chave no localizada"); } }

O compilador no tem como saber se o tipo especificado TKey suporta o operador ==

Programao Genrica

Exemplos
Uma soluo tentar realizar um cast para IComparable, de forma a chamar seu mtodo CompareTo. No entanto, se a classe no implementar IComparable, resulta em erro de execuo

public class MyList<TKey, TValue> { Node<TKey, TValue> head;

public TValue Find(TKey key) { Node<TKey, TValue> current = head;

while (current.NextNode != null) { if (((IComparable)current.Key).CompareTo(key) == 0) return current.Item; else current = current.NextNode; } throw new Exception("Chave no localizada"); } }

Soluo no-type safe

Programao Genrica

Exemplos

public class MyList<TKey, TValue> where TKey : IComparable { Node<TKey, TValue> head;

Outra soluo declarar uma restrio de template, indicando que a classe s public TValue Find(TKey key) poder ser instanciada com tipos que { Node<TKey, TValue> current = head; implementem IComparable
while (current.NextNode != null) { if (current.Key.CompareTo(key) == 0) return current.Item; else current = current.NextNode; } throw new Exception("Chave no localizada"); }

Soluo type safe

Explorando C#

Programao Genrica (Generics) Mtodos de Extenso (Extension Methods) Extenses Funcionais (Delegates, Lambda Expressions) Programao No-segura (Cdigo Unsafe) Compilao (JIT e Cdigo Nativo)

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Explorando C#

Programao Genrica (Generics) Mtodos de Extenso (Extension Methods) Extenses Funcionais (Delegates, Lambda Expressions) Programao No-segura (Cdigo Unsafe) Compilao (JIT e Cdigo Nativo)

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Mtodos de Extenso

Habilitam a extenso de um tipo sem herana Estender cdigo a que no temos acesso til para estender tipos nativos (como arrays[,])

Definidos como mtodos estticos

Chamados como mtodos de instncia

Mtodos de Extenso

Exemplo

Estendendo o tipo inteiro (int)


class Program { static void Main(string[] args) { int a = 5;

bool _par = a.IsEven();


} }

Mtodos de Extenso

Exemplo

Estendendo o tipo inteiro (int)

static class MyExtensions { public static bool IsEven(this int number) { return number % 2 == 0; } }

Mtodos de Extenso

Exemplo

Estendendo o tipo inteiro (int)


class Program { static void Main(string[] args) { bool _par = 5.IsEven(); } }

Explorando C#

Programao Genrica (Generics) Mtodos de Extenso (Extension Methods) Extenses Funcionais (Delegates, Lambda Expressions) Programao No-segura (Cdigo Unsafe) Compilao (JIT e Cdigo Nativo)

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Explorando C#

Programao Genrica (Generics) Mtodos de Extenso (Extension Methods) Extenses Funcionais (Delegates, Lambda Expressions) Programao No-segura (Cdigo Unsafe) Compilao (JIT e Cdigo Nativo)

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Extenses funcionais

Manipulao de funes e expresses

Funes como first-class citizens em C#

Delegates

Permitem declarar o prottipo de uma funo Anlogo de interfaces para classes, porm para funes No necessita de VTBL como no caso de interfaces Similar a bound member function pointers em C++ Permite definir funes de alta ordem (HOFs) Abrem caminho para Anonymous Methods

Anonymous methods so o mecanismo bsico por trs das

Extenses funcionais

Manipulao de funes e expresses

Funes como first-class citizens em C#

Lambda Expressions

Funes annimas

Podem ser declaradas dentro do corpo de outros mtodos/funes Suportam closures carregam variveis livres em seu escopo lxico

Definidas atravs do operador => (leva em)


(parmetros de entrada) => (expresso) (parmetros de entrada) => {comandos;} Ex: Func<double, double> f = x => x + 1;

Extenses funcionais

Manipulao de funes e expresses

Funes como first-class citizens em C#

Expression Trees

Manipulao simblica de expresses

Podem ser usadas para combinar, alterar, modificar cdigo compilvel durante a execuo metaprogramao de maneira fcil possvel examinar expresses definidas por lambdas e process-las de qualquer maneira como por exemplo construindo queries SQL

Mecanismo bsico por detrs da tecnologia LINQ

No entanto, seria necessria uma apresentao inteira para detalhar apenas este assunto.

Extenses funcionais

Exemplo

Delegates

Mtodo nomeado

class Program { delegate double Function(double x); static double Square(x) { return x*x; } static void Main(string[] args) { Function square = Square; double result = square(5); // result = 25 } }

Funes implementando o prottipo especificado pelo delegate podem ser aceitas como parmetros de outras funes.

Extenses funcionais

Exemplo

Lambdas

Expresso annima

class Program { delegate double Function(double x); static void Main(string[] args) { Function square = x => x * x;

Funo declarada no prprio corpo do mtodo Main. 25 } }

double result = square(5); // result =

Nota: Delegates tambm podem ser usados para implementar mtodos annimos, mas a sintaxe no fica to clara

Extenses funcionais

Exemplo

Funes de alta ordem utilizando lambdas

public delegate double Function(double x); static void Main(string[] args) { double r = FuncaoAltaOrdem(-1, Math.Abs, Math.Exp); // r = 2.718... } public static double FuncaoAltaOrdem(double x, params Function[] functions) { // Aplica todas funes sequencialmente foreach (Function f in functions) params: Nmero x = f(x); varivel de

return x;
}

argumentos

Extenses funcionais

Exemplo

Especificando o corpo de uma Thread usando Lambdas


static void Main(string[] args) { Thread t = new Thread(() => { // Tarefa muito complexa e demorada // ... }); t.Start();

Explorando C#

Programao Genrica (Generics) Mtodos de Extenso (Extension Methods) Extenses Funcionais (Delegates, Lambda Expressions) Programao No-segura (Cdigo Unsafe) Compilao (JIT e Cdigo Nativo)

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Explorando C#

Programao Genrica (Generics) Mtodos de Extenso (Extension Methods) Extenses Funcionais (Delegates, Lambda Expressions) Programao No-segura (Cdigo Unsafe) Compilao (JIT e Cdigo Nativo)

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Programao no-segura (unsafe)

Suporte a ponteiros

Manipulao direta da memria Criao de objetos no gerenciados pelo Garbage Collector

Cdigo no-seguro

Ponteiros so tipicamente tidos como viles Muitas linguagens optaram por no oferecer suporte a ponteiros, tendo em vista que ponteiros podem ser mal utilizados, introduzindo mais problemas que solues E isto realmente ocorre.

memory leaks, acesso ilegal a memria, heap corruption, segfaults

Programao no-segura (unsafe)

No entanto, no somente porque um recurso pode ser abusado que todos seus usos se tornam invlidos

A linguagem para o desenvolvedor uma via de expresso de suas idias. No sua limitao.

If something can be done, it surely can be done wrong.

Mesmo em uma linguagem OO, nada impede o desenvolvedor de criar uma nica classe em que todos os mtodos sejam estticos e obter um programa totalmente procedural

Enforar certas restries a um recurso acaba introduzindo

Programao no-segura (unsafe)

Usos vlidos

Performance Performance Performance

Interoperabilidade com cdigo nativo (e.g. APIs em C)

Funes e procedimentos que esperam ponteiros como parmetro

Programao no-segura (unsafe)

Usos vlidos

Exemplo - Arrays bounds check

Um ambiente gerenciado traz muitas vantagens. No entanto, cada vantagem geralmente implica num custo extra de performance. Runtime realiza checagem de limites em arrays para evitar acesso a posies indevidas e levantar exceptions. Como vantagem, no h corrupo da heap por acesso ou escrita indevidos a memria
Com ponteiros, o custo desta verificao eliminado. No entanto, nenhum aviso sera dado caso esta posio no exista. possvel corromper a memria como quiser.

Programao no-segura (unsafe)

Programao no-segura em C#

Palavras chave: unsafe, fixed, stackalloc

Cdigo no seguro pode aparecer somente dentro de blocos unsafe ou mtodos marcados como unsafe:
public void Foo() { unsafe { // ... } } public unsafe void Foo() { // ... }

Programao no-segura (unsafe)

Por que unsafe?

O que um bloco unsafe efetivamente faz dizer ao compilador que, daquele ponto em diante, voc ser o responsvel por garantir que nada d errado. E o compilador acreditar fielmente em voc.
No h problemas em utilizar um cdigo unsafe, mas correto. A dificuldade est em garantir que este cdigo est realmente correto se no estiver, o compilador no ter como lhe avisar.

Programao no-segura (unsafe)

Fixed

O garbage collector pode decidir mover e compactar memria a qualquer momento. necessrio avisar o GC para no tocar na memria que desejamos manipular atravs da keyword fixed
public unsafe void Foo(double[,] a) { fixed (double* ptrA = a) { // pointer wizardry goes here } }

Programao no-segura (unsafe)

Fixed

O garbage collector pode decidir mover e compactar memria a qualquer momento. necessrio avisar o GC para no tocar na memria que desejamos manipular atravs da keyword fixed
public unsafe void Foo(double[,] matrix) { fixed (double* M = matrix) { double* cursor = M; // supondo que matrix tenha dimenses 3x3 double a = *(++cursor); // mesmo que a[0,1] double b = *(cursor + 3); // mesmo que a[1,1]

}
}

Programao no-segura (unsafe)

Stackalloc

Tipos de valor so alocados na Heap Arrays so tipos de valor, logo so alocados na Heap Para alocar uma array na stack, usa-se stackalloc
public unsafe void Foo() { double* array = stackalloc double[10]; for (int i = 0; i < 10; i++) { double ai = array[i]; } }

Programao no-segura (unsafe)

Stackalloc

Tipos de valor so alocados na Heap Arrays so tipos de valor, logo so alocados na Heap Para alocar uma array na stack, usa-se stackalloc
public unsafe void Foo() { double* array = stackalloc double[10]; for (int i = 0; i < 10; i++) { double ai = *(array++); } }

Explorando C#

Programao Genrica (Generics) Mtodos de Extenso (Extension Methods) Extenses Funcionais (Delegates, Lambda Expressions) Programao No-segura (Cdigo Unsafe) Compilao (JIT e Cdigo Nativo)

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Explorando C#

Programao Genrica (Generics) Mtodos de Extenso (Extension Methods) Extenses Funcionais (Delegates, Lambda Expressions) Programao No-segura (Cdigo Unsafe) Compilao (JIT e Cdigo Nativo)

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Compilao

Just-In-Time (JIT)

Compilador JIT roda junto da aplicao

Mtodos ainda no compilados so compilados na primeira execuo (compilao mtodo a mtodo)

Ahead-of-Time (AOT)

Compilador JIT pode no subir junto da aplicao

Toda compilao feita uma nica vez, antes de qualquer execuo, como em compiladores estticos comuns

Compilao

Just-In-Time (JIT)

Compilador JIT roda junto da aplicao

Mtodos ainda no compilados so compilados na primeira execuo (compilao mtodo a mtodo) Uma vez compilado, um mtodo nunca ser recompilado at o fechamento do programa Um programa nunca interpretado

Compilador C# gera cdigo intermedirio (IL)

Durante a execuo, o JIT transforma IL em cdigo de mquina

Compilao

Just-In-Time (JIT)
Cdigo de mquina

Compilao IL
Cdigo intermedirio

Cdigo fonte

C# VB.NET ASM IL C++/CLI

IronPython
Boo Compilao JIT

Compilao

Exemplo (C#)
Exemplo de um programa C# para realizar uma operao lgica and entre dois nmeros.

class Program { private static volatile int i; static void Main(string[] args) { System.Diagnostics.Debugger.Launch(); System.Diagnostics.Debugger.Break(); i = Operation.And(5, 4); // 101 & 100 = 100 (4) Console.ReadKey(); } }

public class Operation { public static int And(int a, int b) { return a & b; }

} Compilao C# para IL

Compilao

Exemplo (IL)

.method private static hidebysig void Main (string[] args) cil managed { .maxstack 8 .entrypoint

IL_0000: call bool [mscorlib]System.Diagnostics.Debugger::Launch() IL_0005: pop IL_0006: call void [mscorlib]System.Diagnostics.Debugger::Break() IL_000b: ldc.i4.5 IL_000c: ldc.i4.4 IL_000d: call int32 Paradigmas.Operation::And(int32, int32) IL_0012: volatile. IL_0014: stsfld modreq([mscorlib]System.Runtime.CompilerServices.IsVolatile) int32 class Paradigmas.Program::i IL_0019: call void [mscorlib]System.Diagnostics.Debugger::Break() IL_001e: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKe IL_0023: pop IL_0024: ret }

Cdigo IL gerado durante a compilao para o mtodo

Compilao

Exemplo (IL)

Cdigo IL gerado durante a compilao para o mtodo And


.method public static hidebysig int32 And (int32 a, int32 b) cil managed { .maxstack 8 IL_0000: ldarg.0 IL_0001: ldarg.1 IL_0002: and IL_0003: ret

Compilao IL para ASM

Compilao

Exemplo (ASM)

<< Demonstrao >>

Acompanhamento da execuo do mesmo programa atravs de um debugger

Ctrl+Alt+D (Disassembly)

O comando Disassembly permite ver o cdigo de mquina gerado pelo JIT (sem otimizaes)

Parmetros da chamada so armazenados em edx e ecx (fastcall calling convention).

Chamada da funo

No corpo da funo, registradores antigos so salvos e os parmetros so resgatados de ecx e edx para serem processados.

Logo aps executar a intruo, o registrador eax armazena o resultado da operao (4).

Aps o trmino da chamada, o resultado da operao (em eax) armazenado na varivel i contida na posio de memria 00189364h.

Compilao

Otimizaes

A maioria das otimizaes realizada pelo compilador JIT Certas otimizaes realizadas pelo JIT so impossveis de serem realizadas por um compilador comum (ahead-of-time) O cdigo visto anteriormente estava em modo de depurao (sem nenhuma otimizao)

Vejamos agora o mesmo cdigo com otimizaes

possvel ver o cdigo com otimizaes executando o programa anexando um debugger durante sua execuo.

O resultado da operao simplesmente movido para dentro da posio de memria de i. O JIT capaz de detectar que o mtodo est sendo chamado com parmetros constantes e no apenas efetuar inlining, mas tambm constant folding durante a execuo.

Compilao

Otimizaes

Otimizaes comuns

Inlining de mtodos e funes Pr-computao de constantes (folding) Propagao de cpias e constantes (propagation) Desenrolamento de loops (unrolling)

Compilao

Otimizaes

Otimizaes comuns

Inlining de mtodos e funes Pr-computao de constantes (folding) Propagao de cpias e constantes (propagation) Desenrolamento de loops (unrolling)

Otimizaes possveis somente durante a execuo

Eliminao da checagem de intervalos Despacho de mtodos virtuais Despacho de mtodos de interface

Explorando C#

Programao Genrica (Generics) Mtodos de Extenso (Extension Methods) Extenses Funcionais (Delegates, Lambda Expressions) Programao No-segura (Cdigo Unsafe) Compilao (JIT e Cdigo Nativo)

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Explorando C#

Programao Genrica (Generics) Mtodos de Extenso (Extension Methods) Extenses Funcionais (Delegates, Lambda Expressions) Programao No-segura (Cdigo Unsafe) Compilao (JIT e Cdigo Nativo)

Exemplo: Verso simples e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods.

Explorando C#

Exemplo

Verso simplificada e eficiente da funo mapcar da linguagem LISP utilizando lambdas, unsafe e extension methods

mapcar executa determinada ao para cada elemento de uma lista

Explorando C#

Exemplo

Verso simplificada da funo mapcar da linguagem LISP


static void Main(string[] args) { var A = new double[,] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, };

var R = A.Map(x => x + 1);


}

Explorando C#

Exemplo

Explorando C#

Exemplo

Estendendo o tipo double[,] com extension methods

static class MatrixExtensions { public static double[,] Map(this double[,] a) { int rows = a.GetLength(0); int cols = a.GetLength(1); double[,] r = new double[rows, cols]; return r; }

Explorando C#

Exemplo

Adicionando suporte a uma expresso definida pelo usurio static class MatrixExtensions
{ public static double[,] Map(this double[,] a, Func<double, double> fun) { int rows = a.GetLength(0); int cols = a.GetLength(1); double[,] r = new double[rows, cols]; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) r[i, j] = fun(a[i, j]); return r; } }

Explorando C#

Exemplo

Removendo bounds checking utilizando cdigo no seguro static class MatrixExtensions


{ public unsafe static double[,] Map(this double[,] a, Func<double, double>

fun) {

int rows = a.GetLength(0), cols = a.GetLength(1), length = a.Length;


double[,] r = new double[rows, cols]; fixed (double* ptrA = a, ptrR = r) { double* src = ptrA, dst = ptrR; for (int i = 0; i < length; i++) *dst++ = fun(*src++); } return r;

}
}

Explorando C#

Exemplo

Fim!

Explorando C#

Pontos ainda a serem explorados...

Continuations (passing style) Closures Lazy Evaluation Memoization LINQ Parallel Extensions Dynamic types Type Inference

Referncias

Jonathan Pryor, Comparing Java and C# Generics.

http://www.jprl.com/Blog/archive/development/2007/Aug31.html http://www.hutteman.com/weblog/2005/04/26-224.html http://blogs.microsoft.co.il/blogs/sasha/archive/2007/02/27/JITOptimizations_2C00_-Inlining_2C00_-and-Interface-MethodDispatching-_2800_Part-1-of-N_2900_.aspx http://csharpindepth.com/Articles/Chapter5/Closures.aspx http://www.codeproject.com/KB/cs/explore_lamda_exp.aspx

Luke Hutteman, C# Continuations useful? Hell yeah!

JIT Optimizations

Closures in C#

Lambda Expressions