Java 8 "default method" versus C# "extend method"

Asked

Viewed 381 times

12

Java 8 introduces the concept of "standard method" to allow adding new features to an interface.

C# provides "extension methods" that allow "adding" methods(features) to existing types.

Taking into account how they are implemented by language and possible usage scenarios, in which aspects they are equivalent and in which they differ?

2 answers

13


The C# extension method alone is not equivalent to the standard Java method. Only when adding the interface can the mechanism be comparable.

It is already immediately clear that in Java the syntax is more convenient.

Standard method

The default Java method is part of the type. There is an inheritance of the interface method for the class method. Here are methods even, the class passes to have them within them. Any type of access to the class, even by reflection will indicate their presence.

In this case if the programmer does not want the default implementation he can write his own to suit that interface. If a class inherits from this class, the implementation of the inherited class can write another implementation smoothly.

The method is virtual, as every method is in interface. It is a mechanism of Runtime according to the interface/class statement. It has the advantages and disadvantages of this. The VM needs to handle the operation.

Extension method

Although it is on top of an interface and it seems that a type that implements the interface has that method, the extension method remains static and totally out of type. Because these methods are static, they function more like functions.

Since the extension method has lower priority, in general this same effect will be obtained if the class implements the method declared in the interface, at any point in the hierarchy, but not in a polymorphic way. It will only work if it is called by the specific type and the compiler knows what that type is. If the decision has to be dynamic, it will be transformed into static and will call the static extension method. It can end up calling what should not or at least what the programmer does not expect.

I can’t guarantee (I don’t know enough) that I don’t have specific extra cases where this could be a problem. One is that it is easier to have name conflicts. Another is that it can give room to dangerous tricks.

Since the method is external to the type, it cannot be accessed directly by the type, it is independent and isolated.

This is a language resource and fully solved by the compiler according to the use of the method (as opposed to its statement). CLR doesn’t even have to deal with this.

One advantage of extension methods (some people say it’s disadvantage) is that you can add new methods to an interface and make all classes that propose to implement the interface already have the method. With the Java engine you have to modify the interface to add the new method.

Now C# has the same mechanism to do something more similar to Java. There are more ambitious proposals that propose other mechanisms, such as traits, but they must not prosper.

I tried to do the same example in Java and C# according to what each language provides:

Java

public class HelloWorld {
    public static void main(String args[]) {
        Veiculo veiculoT = new Veiculo();
        System.out.println("veiculoT");
        veiculoT.diagnostico();
        veiculoT.liga();
        Testador.teste(veiculoT);
        Financeiro.compra(veiculoT);
        System.out.println("---------------");
        Veiculo carro = new Carro();
        System.out.println("carro");
        carro.diagnostico();
        carro.liga();
        Testador.teste(carro);
        Financeiro.compra(carro);
        System.out.println("---------------");
        Carro carro2 = new Carro();
        System.out.println("carro2");
        carro2.diagnostico();
        carro2.liga();
        carro2.buzina();
        Testador.teste(carro2);
        Financeiro.compra(carro2);
    }
}

interface Funcionamento {
    default void liga() {
        System.out.println("Ligou!");
    }
    static void buzina() {
        System.out.println("Buzinou!");
    }
}

class Testador {
    public static void teste(Funcionamento veiculo) {
        System.out.println("Vai testar");
        veiculo.liga();
    }
}

class Financeiro {
    public static void compra(Veiculo veiculo) {
        System.out.println("Comprou N: " + veiculo.id);
        veiculo.diagnostico();
        veiculo.liga();
    }
}

class Veiculo implements Funcionamento {
    public int id = 1;
    public void diagnostico() {
        Funcionamento.super.liga();
        Funcionamento.buzina();
        liga();
        System.out.println("Tudo ok!");
    }
}

class Carro extends Veiculo {
    public void liga() {
        System.out.println("Vrom!");
    }
    public void buzina() {
        System.out.println("bi bi!");
    }
}

Behold working in the ideone. And in the repl it.. Also put on the Github for future reference.

C#

using static System.Console;

public class HelloWorld {
    public static void Main() {
        Veiculo veiculoT = new Veiculo();
        WriteLine("veiculoT");
        veiculoT.diagnostico();
        veiculoT.liga();
        veiculoT.teste();
        veiculoT.compra();
        WriteLine("---------------");
        Veiculo carro = new Carro();
        WriteLine("carro");
        carro.diagnostico();
        carro.liga();
        carro.teste();
        carro.compra();
        WriteLine("---------------");
        Carro carro2 = new Carro();
        WriteLine("carro2");
        carro2.diagnostico();
        carro2.liga();
        carro2.buzina();
        carro2.teste();
        carro2.compra();
    }
}

interface IFuncionamento {
    void liga();
}

static class Funcionamento {
    public static void liga(this IFuncionamento func) => WriteLine("Ligou!");
    public static void buzina() => WriteLine("Buzinou!");
}

static class Testador {
    public static void teste(this IFuncionamento veiculo) {
        WriteLine("Vai testar");
        veiculo.liga();
    }
}

static class Financeiro {
    public static void compra(this Veiculo veiculo) {
        WriteLine("Comprou N: " + veiculo.id);
        veiculo.diagnostico();
        veiculo.liga();
    }
}

class Veiculo : IFuncionamento {
    public int id = 1;
    public void diagnostico() {
        Funcionamento.liga(this);
        Funcionamento.buzina();
        liga();
        WriteLine("Tudo ok!");
    }
    public virtual void liga() => Funcionamento.liga(this);
}

class Carro : Veiculo {
    public override void liga() => WriteLine("Vrom!");
    public void buzina() => WriteLine("bi bi!");
}

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

Note that methods external to type, such as Teste() and Compra() can be called more conveniently in C#. But the method Liga() needs an extra class with extension method to contain the implementation. In addition it needs to have an implementation in the concrete class, even if it just delegates to the extension method, without it there is no polymorphism.

In C# this is a trick that induces errors and makes it difficult to debug and use reflection, and can bring unexpected results to the most naive programmer.

1

I think they’re different things.

C# has no standard method as Java does extensions methods. What our friend did was an attempt to achieve the same result. Of course this way is subject to errors because he tried to do something that in C# does not exist.

Extensions methods are excellent for organizing code and having a fluent programming, outside that it protects the internal elements of your class that will be extended, but, in short, is compare orange to apple.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.