Quelle est votre opinion sur cette décision de conception ? Quels sont ses avantages et ses inconvénients ?
Liens :
Quelle est votre opinion sur cette décision de conception ? Quels sont ses avantages et ses inconvénients ?
Liens :
El Groupe de 4 Le principe crucial de Go est de "préférer la composition à l'héritage" ; Go fait vous le suivez ;-).
Dans un commentaire, vous vous demandiez si l'idée d'incorporation était suffisante pour "remplacer complètement l'héritage". Je dirais que la réponse à cette question est "oui". Il y a quelques années, j'ai joué très brièvement avec un système OO Tcl appelé Snit qui utilise la composition et la délégation à l'exclusion de l'héritage. Snit est encore très différent de l'approche de Go, mais à cet égard, ils ont une base philosophique commune. Il s'agit d'un mécanisme permettant de réunir des éléments de fonctionnalité et de responsabilité, et non d'une hiérarchie pour les classes.
Comme d'autres l'ont dit, il s'agit en fait de savoir quel type de pratiques de programmation les concepteurs du langage veulent prendre en charge. Tous ces choix ont leurs avantages et leurs inconvénients ; je ne pense pas que l'expression "meilleures pratiques" s'applique nécessairement ici. Nous verrons probablement quelqu'un développer une couche d'héritage pour le Go un jour.
(Pour les lecteurs familiers avec Tcl, j'ai trouvé que Snit correspondait un peu plus à la "sensation" du langage que [incr Tcl]
était. Tcl est tout au sujet de la délégation, du moins à ma façon de penser).
Les seules véritables utilisations de l'héritage sont :
Polymorphisme
Emprunter l'implémentation d'une autre classe
L'approche de Go ne correspond pas exactement à la réalité. Considérez cet exemple classique d'héritage et de polymorphisme en Java ( sur la base de ce qui suit ) :
//roughly in Java (omitting lots of irrelevant details)
//WARNING: don't use at all, not even as a test
abstract class BankAccount
{
int balance; //in cents
void Deposit(int money)
{
balance += money;
}
void withdraw(int money)
{
if(money > maxAllowedWithdrawl())
throw new NotEnoughMoneyException();
balance -= money;
}
abstract int maxAllowedWithdrawl();
}
class Account extends BankAccount
{
int maxAllowedWithdrawl()
{
return balance;
}
}
class OverdraftAccount extends BankAccount
{
int overdraft; //amount of negative money allowed
int maxAllowedWithdrawl()
{
return balance + overdraft;
}
}
Ici, l'héritage et le polymorphisme sont combinés, et vous ne pouvez pas traduire cela en Go sans changer la structure sous-jacente.
Je n'ai pas approfondi le Go, mais je suppose que cela ressemblerait à quelque chose comme ça :
//roughly Go? .... no?
//for illustrative purposes only; not likely to compile
//
//WARNING: This is totally wrong; it's programming Java in Go
type Account interface {
AddToBalance(int)
MaxWithdraw() int
}
func Deposit(account Account, amount int) {
account.AddToBalance(amount)
}
func Withdraw(account Account, amount int) error {
if account.MaxWithdraw() < amount {
return errors.New("Overdraft!")
}
account.AddToBalance(-amount)
return nil
}
type BankAccount {
balance int
}
func (account *BankAccount) AddToBalance(amount int) {
account.balance += amount;
}
type RegularAccount {
*BankAccount
}
func (account *RegularAccount) MaxWithdraw() int {
return account.balance //assuming it's allowed
}
type OverdraftAccount {
*BankAccount
overdraft int
}
func (account *OverdraftAccount) MaxWithdraw() int {
return account.balance + account.overdraft
}
Comme indiqué dans la note, il s'agit d'une manière totalement erronée de coder puisque l'on fait du Java en Go. Si l'on devait écrire une telle chose en Go, elle serait probablement organisée de manière très différente.
L'incorporation permet une délégation automatique. Cela ne suffit pas en soi à remplacer l'héritage, car l'incorporation ne fournit aucune forme de polymorphisme. Les interfaces de Go fournissent du polymorphisme, mais elles sont un peu différentes des interfaces auxquelles vous êtes peut-être habitué (certaines personnes les comparent au typage en canard ou au typage structurel).
Dans d'autres langages, les hiérarchies d'héritage doivent être conçues avec soin, car les changements sont vastes et donc difficiles à réaliser. Go évite ces écueils tout en offrant une alternative puissante.
Voici un article qui approfondit un peu plus la POO avec Go : http://nathany.com/good
Je viens tout juste d'apprendre à connaître le go, mais puisque vous demandez un avis, je vais vous en donner un sur la base de ce que je sais jusqu'à présent. L'intégration semble être typique de beaucoup d'autres choses en Go, qui est un support explicite du langage pour les meilleures pratiques qui sont déjà faites dans les langages existants. Par exemple, comme l'a noté Alex Martelli, le Gang of 4 dit "préférer la composition à l'héritage". Non seulement Go supprime l'héritage, mais il rend la composition plus facile et plus puissante qu'en C++/Java/C#.
J'ai été intrigué par des commentaires tels que "Go n'apporte rien de nouveau que je ne puisse déjà faire dans le langage X" et "pourquoi avons-nous besoin d'un autre langage ?". Il me semble que dans un sens, Go n'apporte rien de nouveau qui ne pouvait pas être fait avant avec un peu de travail, mais dans un autre sens, ce qui est nouveau est que Go facilitera et encouragera l'utilisation des meilleures techniques qui sont déjà en pratique en utilisant d'autres langages.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.