Chamar métodos static por tipo variável é ilegal - Parte I

02/29/2008 09:55:00 By Felipe Pessoto

Considere o seguinte:

public class C { public static void M() { /*blablabla*/ } }
public class D : C { public new static void M() { /*blablabla*/ } }
public class E<T> where T : C { public static void N() { T.M(); } }

Isso é ilegal. Nós não podemos chamar um método static sob um tipo variável. A questão é, por quê? Nós sabemos que T deve ser um C, e C tem um método static M, então por que isto não é válido?

Espero que você concorde que uma das seguintes afirmações deve ser verdadeira:

1) Isto é inválido.
2) E<T>.N() chama C.M() não importa o que T é.
3) E<C>.N() chama C.M() mas E<D>.N() chama D.M().

Se nós pegarmos a opção 2, então isto é tão sem sentido quanto totalmente inútil. O usuário irá esperar que D.M() seja chamado se T for um D. Porque senão para que teriamos o trabalho de chamar T.M() em vez de C.M() se ele irá "sempre chamar C.M()"?

Se pegarmos a opção 3, então nós temos uma violação dos princípios de design do núcleo dos métodos static, o princípio que lhes deu o nome. Métodos estáticos são chamados “static” porque eles podem sempre determinar exatamente, em tempo de compilação, qual método será chamado. Ou seja, o método pode ser resolvido unicamente por análise estática do código.

Só sobra a opção 1.

Perguntas relacionadas são frequentemente abordadas, de várias formas. Muitas pessoas costumam perguntar porque C# não suporta métodos “virtual static”. Mas o que elas estão querendo dizer? Pois “virtual” e “static” são opostos! “virtual” significa“determinar o método a ser chamado baseado nas informações de tipo em tempo de execução”, e “static” significa“determinar o método a ser chamado unicamente baseado na análise estática em tempo de compilação”.

Na verdade o que as pessoas querem é um outro tipo de método, que não seja static, instanciado ou virtual. Nós poderiamos chegar à uma nova espécie de método que se comporta como a opção 3. Isto é, um método associado com o tipo (como um static), que não tem um argumento this "non-nullable" (diferente de um instanciado ou virtual), mas um onde o método chamado deve depender do tipo construído sobre o T (diferente de um static, o qual deve ser determinado em tempo de compilação).

Porque os operadores em C# são sempre static?

02/28/2008 15:41:00 By Felipe Pessoto

Porque os operadores em C# são sempre static? No C++ um operador sobrecarregado pode ser implementado por métodos static, instanciados ou virtual. Há alguma razão para esta regra no C#?

Antes de irmos direto ao assunto, há um ponto que vale a pena discutirmos um pouco. Raymond Chen imediatamente disse que tínhamos que voltar um pouco para o passado do C#. O design da linguagem C# não é um processo de subtração. C# não é um Java/C++ com as partes que não se ligavam removidas.

A questão que devemos nos perguntar sobre uma característica potencial da linguagem é "os benefícios trazidos irão justificar os custos?". E os custos são consideravelmente mais que somente os dólares gastos com designing, desenvolvimento, testes, documentação e manutenção. Há mais pequenos custos, como, este recurso tornará mais difícil a troca do algoritmo de inferência de tipo no futuro? Será que isso nos levará a um mundo onde não poderemos fazer alterações sem introduzir incompatibilidades? E por ai vai...

Neste caso específico, os benefícios são pequenos. Se você quer ter um operador virtual sobrecarregado no C# você pode construir um contornando as partes static. Por exemplo:

public class B {
public static B operator+(B b1, B b2) { return b1.Add(b2); }
protected virtual B Add(B b2) { // ...

E você terá ele. Então, os benefícios são pequenos. Mas os custos são grandes. Operadores instanciados no estilo C++ são esquisitos. Por exemplo, eles quebram a simetria. Se você definir um operador + que recebe um C e um int, então c+2 é válido mas 2+c não é, isso que rompe nosso conceito sobre como o operador de adição deve se comportar.

Similarmente, com operadores virtual no C++, o argumento à esquerda é o que serve de parâmetro para chamada virtual. Então novamente, nós temos uma assimetria entre os lados esquerdo e direito. Realmente o que você quer para a maioria dos operadores binários é que sejam comutativos -- você quer que o operador seja virtualizado nos tipos de ambos argumentos, não somente o do lado esquerdo. Mas nem o C# nem C++ suportam comutação nativamente. (Muitos problemas do mundo real devem ser resolvidos se tivermos comutação; por uma coisa, o visitante padrão torna-se trivial.)

E finalmente, no C++ você pode somente definir um operador sobrecarregado sobre um tipo que não seja um ponteiro, isto é um só pode definir para tipos por valor. Isto quer dizer que quando você ver c+2 e reescrever como c.operator+(2), você está garantindo que c não é um ponteiro nulo porque ele nunca será um ponteiro! C# também faz a distinção entre valores e referência, mas seria muito estranho se um operador instanciado sobrecarregado fosse apenas definido sobre tipos por valor "non-nullable", e também seria estranho se c+2 pudesse gerar uma exceção "null reference".

Por isso foi decidido não adicionar operadores sobrecarregados por instância ou virtual no C#.

Atualização para Visual Studio 2008 e Visual Web Developer Express 2008

02/28/2008 11:17:00 By Felipe Pessoto

Pré-Requisitos: 

1.Microsoft Visual Studio 2008 ou Visual Web Developer Express 2008.

2.Feche todas as janelas do Visual Studio ou VWD express antes de instalar a atualização. Se algum deles estiver aberto enquanto o hotfix é instalado, pode causar uma variedade de problemas como certos componentes não serem atualizados corretamente.

Download

Correções:

Performance do HTML Source view 

  • Editor de código fonte congela por poucos segundos quando se está digitando em uma página com um controle personalizado que tem mais que dois leveis de sub-propriedades.

  • Menu de contexto ao clicar com o botão direito em "View Code" leva um longo tempo  para aparecer. 

  • Visual Studio tem um comportamento muito lento quando se abre um documento HTML muito grande.

  • Visual Studio tem problemas de resposta quando está trabalhando com grandes arquivos HTML que tem certos elementos.

  • O Tab/Shift-Tab (Indentar/Desindentar) é lento com grandes seleções HTML.

Performance do Design view

  • Digitação lenta no 'design view' com certas configurações.

Edição de HTML

  • Aspas não são inseridas depois dos atributos Class ou CssClass mesmo quando a opção está ativada.

  • Visual Studio trava quando o elemento ServiceReference volta para a página atual.

Edição de JavaScript

  • Quando abrindo um arquivo JavaScript,  a colorização do script cliente é algumas vezes atrasada vários segundos.

  • Intellisense do JavaScript não funciona se uma propriedade com string vazia é encontrada antes da linha que está sendo editada.

Performance do build do Web Site

  • Build é muito lento quando a pasta Bin contém muitos arquivos de assemblies e .refresh.

Covariância e Contravariância em C#, Parte Três: Variância em Grupo de Métodos

02/13/2008 08:45:00 By Felipe Pessoto

Anteriormente discutimos como a covariância numa array não funciona corretamente no C# (e Java, assim como uma série de outras linguagens). Agora, um tipo de variância válida suportada no C# 2.0: conversões de grupo de métodos em delegates. Este é um tipo mais complicado de variância, por isso vou explicar com mais detalhes.

Suponha que você tem um método que retorna um objeto Girafa.

static Girafa CriarGirafa() { }

E que você tem um delegate representando uma função que não recebe argumentos e retorna um Animal. Isto é, Func<animal>. Deveria esta conversão ser válida?

Func<animal> func = CriarGirafa;

Ao invocar Func é esperado que um Animal seja retornado. A função atual chamada pelo delegate sempre retorna uma Girafa, a qual é um Animal, então o invocador da função nunca recebe nada que ele não seja capaz de lidar. Não há problemas no sistema de tipo aqui. Portanto nós podemos criar métodos para delegate usando conversões covariantes nos seus tipos de retorno.


Agora vamos supor que você tem dois métodos, um que recebe Girafa e um que recebe um Animal:

void Foo(Girafa g) { }
void Bar(Animal a) { }

e um delegate que retorna vazio e recebe um argumento do tipo Mamifero:

Action<Mamifero> action1 = Foo; // inválido
Action<Mamifero> action2 = Bar; // válido

Por quê a primeira atribuição é inválida? Porque quem invocar o action1 pode passar por exemplo um tipo Tigre(já que seria derivado de Mamifero), mas Foo não pode receber um Tigre, somente uma Girafa(e seus derivados)! A segunda atribuição é válida porque Bar pode receber qualquer Animal.

No exemplo anterior preservamos a direção de atribuição: Girafa é menor que Animal, então o método que retorna Girafa é menor que o delegate que retorna um Animal. Neste exemplo, nós revertemos a direção de atribuição: Mamifero é menor que Animal, então o método que recebe Animal é menor que o delegate que recebe um Mamifero. Porque a direção está invertida, conversões de grupo de métodos para delegate são contravariantes nos tipos de seus argumentos.

Percebe que tudo falado acima aplica-se apenas em tipos por referência. Nunca diga algo como "Bem, todo int cabe em um long, então um método que retorna um int pode ser atribuído para uma variável do tipo Func<long>".

Vista SP1 e Windows Server 2008 lançados para os fabricantes

02/08/2008 11:13:00 By Felipe Pessoto

O Service Pack 1 do Windows Vista, e também o Windows Server 2008, ambos versões finais (RTM), foram lançados, mas somente para os fabricantes.

Para os usuários finais, o download do SP1 do Windows Vista estará disponível na noite do dia 18 de fevereiro, segundo a Microsoft. O Windows Server 2008 será anunciado oficialmente em 27 de fevereiro.

Como sempre acontece, as versões RTM acabam caindo nas redes P2P e já é possível encontrá-los com certa facilidade. Só é preciso cuidado pois são fontes nada confiáveis e uma boa isca usada por scammers.

O Service Pack 3 do Windows XP já está em RC2 e desta vez também em versão para o Português Brasileiro. Fala-se que o RC2 provavelmente será a versão final, se não aparecer nenhum bug. De qualquer forma, a versão RTM está prevista para a noite do dia 23 de março.