Moja odpowiedź: zły wybór projektu. ;-)
To interesująca debata poświęcona wpływowi składni. Moim zdaniem rdzeniem tego argumentu jest to, że decyzja projektowa doprowadziła do zapieczętowanych klas statycznych. Skupiasz się na przejrzystości nazw klas statycznych pojawiających się na najwyższym poziomie zamiast ukrywania („mylenia”) za imionami dzieci? Można sobie wyobrazić implementację języka, która mogłaby uzyskać bezpośredni dostęp do bazy lub dziecka, co jest mylące.
Pseudo przykład, zakładający statyczne dziedziczenie, został w jakiś sposób zdefiniowany.
public static class MyStaticBase
{
SomeType AttributeBase;
}
public static class MyStaticChild : MyStaticBase
{
SomeType AttributeChild;
}
doprowadziłoby do:
// ...
DoSomethingTo(MyStaticBase.AttributeBase);
// ...
co może (mogłoby?) wpłynąć na to samo miejsce do przechowywania
// ...
DoSomethingTo(MyStaticChild.AttributeBase);
// ...
Bardzo mylące!
Ale poczekaj! Jak kompilator poradziłby sobie z MyStaticBase i MyStaticChild posiadającymi taki sam podpis zdefiniowany w obu? Jeśli dziecko zastąpi, niż mój powyższy przykład, NIE zmieniłoby tego samego magazynu, może? Prowadzi to do jeszcze większego zamieszania.
Uważam, że istnieje silne uzasadnienie przestrzeni informacyjnej dla ograniczonego dziedziczenia statycznego. Więcej o limitach wkrótce. Ten pseudokod pokazuje wartość:
public static class MyStaticBase<T>
{
public static T Payload;
public static void Load(StorageSpecs);
public static void Save(StorageSpecs);
public static SomeType AttributeBase
public static SomeType MethodBase(){/*...*/};
}
Następnie otrzymujesz:
public static class MyStaticChild : MyStaticBase<MyChildPlayloadType>
{
public static SomeType AttributeChild;
public static SomeType SomeChildMethod(){/*...*/};
// No need to create the PlayLoad, Load(), and Save().
// You, 'should' be prevented from creating them, more on this in a sec...
}
Sposób użycia wygląda następująco:
// ...
MyStaticChild.Load(FileNamePath);
MyStaticChild.Save(FileNamePath);
doSomeThing(MyStaticChild.Payload.Attribute);
doSomething(MyStaticChild.AttributeBase);
doSomeThing(MyStaticChild.AttributeChild);
// ...
Osoba tworząca statyczne dziecko nie musi myśleć o procesie serializacji, o ile rozumie wszelkie ograniczenia, które mogą zostać nałożone na silnik serializacji platformy lub środowiska.
Statyka (singletony i inne formy „globałów”) często pojawiają się wokół pamięci konfiguracji. Dziedziczenie statyczne pozwoliłoby na czystą reprezentację tego rodzaju alokacji odpowiedzialności w składni w celu dopasowania do hierarchii konfiguracji. Chociaż, jak pokazałem, istnieje duże prawdopodobieństwo ogromnej dwuznaczności, jeśli zostaną zaimplementowane podstawowe koncepcje dziedziczenia statycznego.
Uważam, że właściwym wyborem projektowym byłoby umożliwienie dziedziczenia statycznego z określonymi ograniczeniami:
- Żadnego zastąpienia. Dziecko nie może zastąpić podstawowych atrybutów, pól ani metod ... Przeciążenie powinno być w porządku, o ile istnieje różnica w podpisie pozwalająca kompilatorowi na uporządkowanie dziecka i bazy.
- Zezwalaj tylko na ogólne podstawy statyczne, nie możesz dziedziczyć po nieogólnych podstawach statycznych.
Nadal możesz zmienić ten sam sklep za pomocą ogólnego odniesienia MyStaticBase<ChildPayload>.SomeBaseField
. Byłbyś jednak zniechęcony, ponieważ typ ogólny musiałby zostać określony. Natomiast odniesienie dziecko byłoby czystsze: MyStaticChild.SomeBaseField
.
Nie jestem pisarzem kompilatorów, więc nie jestem pewien, czy coś mi brakuje na temat trudności we wdrażaniu tych ograniczeń w kompilatorze. To powiedziawszy, jestem głęboko przekonany, że istnieje przestrzeń informacyjna, która wymaga ograniczonego dziedziczenia statycznego, a podstawową odpowiedzią jest to, że nie możesz tego zrobić z powodu złego (lub zbyt prostego) wyboru projektu.