Surcharger des membres statiques: Absurde?

Suis-je vraiment le seul à être souvent tenté d’écrire des choses absurdes comme?:

abstract class MyAbstractClass
{
	public static abstract string MyString	{ get; }
}

Bien sûr que c’est absurde, en tout cas en .Net/Mono, Java et j’imagine dans la plupart sinon tous les langages object compilés.
Pour ceux qui trouveraient le code ci-dessus légitime: Un membre statique est attachée à la classe où elle est définie. Vouloir le surcharger _ce qu’implique évidemment le abstract__, n’a donc pas de sens.

D’ailleurs, il faut dans tous les cas toujours explicitement indiquer la classe du membre statique que l’on appelle.

class Class1
{
	public static void MyMethod()
	{	Console.WriteLine("I am Class1.MyMethod");	}
}
 
class Class2:Class1{ }
 
class Class3:Class2
{
	public static new void MyMethod()
	{	Console.WriteLine("I am Class3.MyMethod");	}
}
 
class Main
{
	public static void Main(string[] args)
	{
		Class1.MyMethod();	// prints "I am Class1.MyMethod"
		Class2.MyMethod();	// prints "I am Class1.MyMethod"
		Class3.MyMethod();	// prints "I am Class3.MyMethod"
 
	}
}

Le terme statique n’est pas anodin. Il a été choisi pour indiquer qu’il ne peut y avoir d’ambiguité pour le compilateur sur la définition du membre à utiliser.
Il s’oppose naturellement à dynamique où il se peut que le choix du membre ne puisse être déterminé qu’au moment de l’éxecution du code.

Par exemple:

class Class1
{
	public void MyMethod()
	{	Console.WriteLine("I am Class1.MyMethod");	}
}
 
class Class2:Class1{ }
 
class Class3:Class2
{
	public new void MyMethod()
	{	Console.WriteLine("I am Class3.MyMethod");	}
}
 
class Main
{
	public static void Main(string[] args)
	{
		this.Test(new Class1());
		this.Test(new Class2());
		this.Test(new Class3());
	}
 
	public void Test(Class1 obj)
	{	obj.MyMethod();	}
 
}

La méthode appelée par obj.MyMethod(); dépend du type de obj.
Le compilateur ne peut savoir quelle méthode sera appelée et le lien se fera au moment de l’éxecution.

Alors, si le code présenté au départ est si absurde, pourquoi vouloir l’écrire ?

Il me semble que c’est principalement parce que deux définitions de la notion de membre statique peuvent avoir des zones de friction:
- D’une part, la notion d’attachement à la classe par opposition à l’instance.
- D’autre part la notion d’immuabilité du type pour le compilateur.

La première notion est purement conceptuelle:
_ Tous les insectes ont 6 pattes
_ Cette fourmi transporte une feuille

Puisque tous les insectes ont 6 pattes, il peut paraître logique de définir cette valeur au niveau de la classe, et donc en utilisant un membre statique.

class Insect
{
	public static int NbLegs
	{
		get:{ return 6; }
	}
}

Après tout, définir une valeur pour l’instance impliquerait conceptuellement que cette valeur puisse changer d’une instance à l’autre, non ?

Imaginons maintenant que nous désirions créer une interface pour définir l’ensemble des animaux dont on connaît le nombre de pattes par famille.

interface AnimalsWeKnowTheNumberOfLegs{...}

Le fait que le nombre de pattes sera connu de toutes les instances implémentant cette interface est bien évidemment à indiquer

interface AnimalsWeKnowTheNumberOfLegs
{..
	int NbLegs{	get;	}
..}

Ouis, mais si on trouve plus logique que la valeur de la propriété soit attachée à la classe plutôt qu’à ses instances ?

interface AnimalsWeKnowTheNumberOfLegs
{..
	static int NbLegs{	get;	}
..}

File=AnimalsWeKnowTheNumberOfLegs.cs, Line=10, Column=24, Type=Error, Priority=Normal, Description=The modifier `static’ is not valid for this item(CS0106)

ARghle…

Mais arrêtons-nous un moment.
Que cherche-t-on à exprimer ici ?

Ce que l’on aimerait, c’est exprimer que le nombre de pattes des instances des classes qui héritent de AnimalsWeKnowTheNumberOfLegs est une valeur définie pour leur classe.
Je sais, c’est un peu tordu.

En traduisant cette proposition en utilisant un membre statique, on commet un contre-sens:

Une propriété de la classe != Une propriété partagée par toutes les instances de la classe!!

La classe des insectes n’a pas 6 pattes! La classe des insectes n’a pas de pattes du tout! C’est une classe, pas un animal enfin!
Seuls les insectes ont 6 pattes.

Oui, mais comment alors exprimer le fait que la propriété est partagée par toutes les instances de la classe ?

- Et bien, en .Net/Mono au moins, on dispose à cet effet au sein d’une classe donnée du mot-clé const.
On peut alors retourner le const dans le get de notre propriété.

Par contre, on n’a toujours pas de moyen de forcer la définition d’un const dans une classe enfant.
En d’autre termes, impossible de spécifier un const dans une interface, en temps de membre abstrait ou même virtuel.

- En Java, on ne peut pas. A ma connaissance, final est l’équivalent de readonly et pas de const.

- Pour les langages prototype-based, il suffit de définir la propriété sur le prototype.
Ex en Javascript:

var o = {
};
 
var F = function(){};
F.prototype = o;
another_o = new F(); // o and another_o share the same prototype
 
o.prototype['my_shared_value'] = 25;
 
alert(o.my_share_value);
alert(another_o.my_shared_value);

- PHP a aussi un const. Mais les variables ainsi définies sont appelées comme des variable statique.

<?php
class MyClass
{
	const MyConstant = 'A constant';
}
 
echo MyClass::MyConstant;
$a = new MyClass();
echo $a->MyConstant;	// ERROR!
?>

A noter que PHP autorise à écrire « static abstract function test() ».

Il est clair que ma tentation de forcer la définition de membres statiques vient de là.

- En python et python-like, la confusion est là aussi possible. Le mot-clé self permet d’appeler indiféremment des membres statiques ou non.
Le code suivant est valide en Boo:

class MyClass():
	_string = "A string"
 
	public def constructor():
		self.StaticMethod()
		Console.WriteLine(self._string)
 
	public static def StaticMethod():
		pass

En conclusion, je ne vois pas de réelle solution pour forcer dans une interface ou une classe abstraite une propriété dont la valeur serait comune à toutes les instances de la classe.
Cela n’empêche pas bien sûr de coder mais la responsabilité de l’immuabilité d’une valeur d’une propriété pour une classe donnée continuera à échoir au programmeur.

Pour ma part, il me semble qu’il manque aux langages objets class-based un niveau d’abstraction pour définir cet ensemble de valeurs de propriétés communes ax instances d’une classe.
Ce niveau est justement celui définit par la notion de prototype dans les langages prototype-based.

A quand des langages permettant enfin des choses comme ceci ?:

class Insect(Animal):
	prototype:
		public NbLegs = 6;
 
	public def constructor():
		pass
  1. Aucun commentaire pour l'instant

  1. Aucun trackback pour l'instant