Welcome to GASP Sign in | Join | Help

Paulo Morgado

Tudo sobre Arquitectura de Software
Esticando a inferência de tipos

Nota: Código em itálico não corresponde à sintaxe do C# 3.0.

Inferência do tipo de variáveis locais

O C# 3.0 trouxe-nos a possibilidade da inferência do tipo de uma variável local, cujo principal objectivo foi suportar o LINQ. O resultado de uma consulta (query) pode ser uma implementação de IEnumerable<T> ou IQueryable<T> uma instância de T onde T pode ser uma projecção, o que implica que T é um tipo anónimo.

Tomemos a consulta seguinte como exemplo:

from p in persons
select new { Name = p.FirstName + " " + p.LastName, Age = p.Age };

Se persons for uma implementação de IEnumerable<Person>, o resultado da consulta será uma implementação de IEnumerable<T> onde T é um tipo anónimo.

Coloca-se então uma questão: Como é que declaramos uma variável para receber o resultado da consulta?

A solução encontrada foi a introdição da nova palavra-chave var que instrui o compilador para determinar o tipo do resultado da consulta. Sendo assim, tudo é que é ncessário para declarar uma variável para receber  resultado da consulta é:

var q =
    from p in persons
    select new { Name = p.FirstName + " " + p.LastName, Age = p.Age };

Uma vez que o compilador consegue inferir o tipo de algo que arece tão complexo, é óbvio que será capaz de inferir o tipo de algo tão simples directo como:

var v = new Dictionary<Point, Stack<Person>>();

Obviamente, é o mesmo que:

Dictionary<Point, Stack<Person>> v = new Dictionary<Point, Stack<Person>>();

com menos digitação e menor margem para erros de digitação.

Inferência do tipo de campos

A mesma técnica poderia ser aplicada à inferência do tipo de campos:

class Class
{
    private someDicionary = new Dictionary<string, List<string>>();

    // ...
}

com os mesmos benefícios de menos digitação e menor margem para erros de digitação.

Se a inferência do tipo de campos fosse aplicada a campos públicos, deveria ser aplicado o seguinte constrangimento: o tipo inferido não pode ser ou ter como parâmtero um tipo anónimo.

Mas eu não recomendaria o seu uso porque facilmente uma simples modificação na inicialização do campo poderia trazer alterações menos óbvias à interface pública da classe.

Inferência do tipo de parâmetros e retorno de métodos

Dado que a inferência de tipos seria possível fora de métodos, deveria ser permitida em parâmetros e valores de retorno? Algo como isto:

class SomeClass
{
    private listOfStuff = new List<Stuff>();

    public void DoIt()
    {
        if (CreateList(out this.listOfStuff))
        {
            ProcessList(ref this.listOfStuff);

            this.listOfStuff = TransformList(this.listOfStuff);
        }
    }

    private bool CreateList(var out list)
    {
        list = new List<Stuff>();
        return true;
    }

    private void ProcessList(var ref list)
    {
        // ... 
    }

    private var TransformList(var list)
    {
        return list;
    }
}

que tem um aspecto algo estranho e confuso, no mínimo. Não deveríamos ir por aí.

Inferência de construtores

Desde o meu primeiro contacto com a inferência do tipo de variaveis locais que tenho a sensação de que se poderia ter ido mais longe.

Olhemos para este conjunto hipotético de declarações:

Dictionary<Point, Stack<Person>> v = new();
Point p = new(1, 2);

Será fácil, tanto para o compilador como para um humano que leia o código, determinar que é o mesmo que:

Dictionary<Point, Stack<Person>> v = new Dictionary<Point, Stack<Person>>();
Point p = new Point(1, 2);

E isto pode ser mais poderoso que a inferência do tipo de variáveis locais e usado em mais cenários:

class Class
{
    private Dictionary<string, List<string>> someDicionary = new();
    private Point p;

    public Class()
    {
        this.p = new(1, 1);
    }

    public void SomeMethod()
    {
        AnotherMethod(new());
    }

    private void AnotherMethod(List<string> arg)
    {
        // ...
    }
}
Onde parar?

O compilador poderia com igual facilidade inferir o tipo da variável local neste caso:

public void SomeMethod()
{
    var v = new();
    AnotherMethod(v);
}

Queremos ir por aí? Não me parece.

Ambiguidades

O C# 3.0 trouxe-nos também inicializadores de objectos. Em vez disto:

XmlReaderSettings settings = new XmlReaderSettings();
settings.CheckCharacters = false;
settings.IgnoreWhitespace = true;

XmlReader reader = XmlReader.Create("someURI", settings);

podemos apenas escrever isto:

XmlReaderSettings settings = new XmlReaderSettings() { CheckCharacters = false, IgnoreWhitespace = true };

XmlReader reader = XmlReader.Create("someURI", settings);

ou isto:

XmlReader reader = XmlReader.Create("someURI"new XmlReaderSettings() { CheckCharacters = false, IgnoreWhitespace = true });

Não seria bom escrever apenas isto?

XmlReaderSettings settings = new() { CheckCharacters = false, IgnoreWhitespace = true };

Os inicializadores de objectos do C# 3.0 também permitem omitr os parentesis do construtor:

XmlReaderSettings settings = new XmlReaderSettings { CheckCharacters = false, IgnoreWhitespace = true };

que levaria a:

XmlReaderSettings settings = new { CheckCharacters = false, IgnoreWhitespace = true };

que tem a mesma forma que a criação de um objecto de um tipo anónimo e poderia causar algumas ambiguidades.

Mas seria bom escrever apenas isto:

XmlReader reader = XmlReader.Create("someURI", new { settings.CheckCharacters = false, settings.IgnoreWhitespace = true });

Não seria?

Posted: Monday, April 28, 2008 12:09 AM by Paulo Morgado

Comments

Raphael, MagoDigital said:

Cara realmente você mostrou varias ideais que pelo visto seria possível a implementação. Quem sabe talvez isso apareça em uma nova versão!

# April 28, 2008 12:21 PM

Paulo Morgado said:

Algumas seriam muito perigosas porque levariam a ambiguidades. Tem de ser uma escolha muito responsável.

# April 28, 2008 2:39 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS