4 ms·
One of the greatest lingering flaws in both C# and Java is the lack of metaclasses. Because classes aren't real objects and therefore not necessarily also inst
by oop17 9y ago
One of the greatest lingering flaws in both C# and Java is the lack of metaclasses.
Because classes aren't real objects and therefore not necessarily also instances of other classes (their metaclasses) as they would be in Smalltalk, there is no class-side equivalent of "self/this," nor of "super." In effect, you cannot write static (class) methods that call other static methods without explicitly referencing the classes on which those other methods are defined, completely breaking class-side inheritance and rendering class behavior (and instance creation in particular) needlessly brittle.
I believe the explosion of factories, abstract factories, and just generally over-engineered object construction and initialization schemes in Java and C# would have been side-stepped if both languages had always had a proper metaclass hierarchy paralleling the regular class hierarchy, as well as some form of local type inference.
- ska 9y agoWhatever the reasons behind it, it is clear that a lot of the effective and high impact industrial languages at various levels of the stack (e.g. c++, ada, Java/C#, python, perl, javascript,etc.) have not managed to incorporate some of the real wisdom learned in earlier systems (e.g. smalltalk an some lisps for OO, etc.) If this was in fact avoidable, it is a sad fact.
- le-mark 9y agoThis type stupid bloviating is why programming will never be a proper engineering discipline. There are two ways to implement oop: classes aka "object templates" or prototypes. Educate your selves people!
- marktangotango 9y agoThis a valid observation, why have no down voters commented? Oop implementation was studied extensively in 80's, CLOS was very contentious in fact. The lack of training and perspective is stunning.
- ska 9y agoThe tone makes it difficult to tell, but I think you are supporting my thesis - mistakes of the past are, in fact, being repeated. Engineering disciplines succeed by a) learning the science and b) applying it properly. We do not do that well in programming. So yes, educate yourself, and then take the lessons to heart.
- klodolph 9y ago> I believe the explosion of factories, abstract factories, and just generally over-engineered object construction and initialization schemes in Java and C# would have been side-stepped if both languages had always had a proper metaclass hierarchy paralleling the regular class hierarchy, as well as some form of local type inference. That's a bit harsh. "Factory" is a term that became prominent in Java as a result of the language design decision not to include first-class functions, so any time you see "Factory" just think "function that returns an object", and any time you see "AbstractFactory", think, "type of function that returns an object". In C# you can just use delegates and the explosion of factories isn't really there. I'd say your opinion of this explosion might change if you work in a good codebase which makes sensible use of techniques like IoC. Yes, it feels a bit silly to have a component in your project which does nothing more than instantiate objects, but you end up with classes that are much more cleanly defined in terms of the interfaces they expose and consume, and you can write unit tests that don't make you feel like you're damaging your code base to get the unit test to work. At least, when it goes well. My experience with metaclass programming (a fair bit of Python metaclass programming) is that it can often be replaced by generics, reflection, or various code generation tricks in C#, and I don't end up missing metaclass programming that much. Metaclass programming isn't a silver bullet, it's a tool that complements other tools in the right toolbox (Python, Smalltalk) but would just get in the way in other toolboxes (C#, Go). There's a narrative here that we're somehow "neglecting" the lessons we learned with old systems like Smalltalk, Lisp, etc. when we make languages. It's a seductive narrative but I think it's mostly papering over the sentiment that language X isn't like my favorite language, Y, and therefore it's bad. I welcome the proliferation of different programming paradigms, and besides a few obvious features (control structures, algebraic notation for math) there are few features that make sense in every language. That especially includes metaprogramming, generics, reflection, macros, and templates.
- kazinator 9y agoFirst class functions aren't replacements for factories. An abstract factory provides several methods for constructing related objects of different types. The objects come from different type hierarchies, whose inheritance structures mimic each other. For instance, you might have a hierarchy of EncryptionStream and EncryptionKey objects. Both derive in parallel into AESEncryptionStream and AESEncryptionKey. Then you have an EncryptionFactory base class/interface which has MakeStream and MakeKey methods. This is derived into AESEncryptionFactory, whose MakeStream makes an AESEncryptionStream and whose MakeKey makes an AESEncryptionKey. The client just knows that it has an EncryptionFactory which makes some kind of stream and some kind of key, which are compatible. AbstractFactory doesn't specifically address indirect construction or indirect use of a class, but it does solve a problem that can also be addressed with metaclasses. If we can just hold a tuple of classes, and ask each one to make an instance, then that kind of makes AbstractFactory go away. The thing is that in a language like Java, these factories have rigid methods with rigid type signatures. The MakeKey of an EncryptionFactory will typically take the same parameters for all key types. The client doesn't know which kind of stream and key it is using, and uses the factory to make them all in the same way, using the same constructor parameters (which are tailored to the domain through the EncryptionFactory base/interface). If we have a class as a first class object (such as an instance of a metaclass), that usually goes hand in hand with having a generic construction mechanism. For instance, in Common Lisp, constructor parameters are represented as keyword arguments (a de facto property list). That bootstraps from dynamic typing. All object construction is done with the same generic function in Common Lisp, the generic function make-instance. Thus all constructors effectively have the same type signature. Without solving the problem of how to nicely have generic constructors, simply adding metaclasses to Java would be pointless. This is possibly a big part of the reason why the feature is absent.
- kazinator 9y agoOver-engineered construction schemes are a result of multiple factors. One is simply the static type system which gives rise to overly rigid type signatures. Class constructors tend to exhibit a variety of type signature. Even when objects are derived from the same base type and substituted for each other, the way they are constructed can be quite different. In a dynamic language, we can handle all construction with the same kind of function: something that takes a "property list". Because of that, we can have a "virtual constructor". That can be a method on a meta-class to create an instance, or just something built in: some make-new-object function which takes a type and a list of generic constructor arguments that any type can handle. This is very easy to indirect upon. Adding meta-classes in Java wouldn't solve the problem of how to make construction generic.
- seanmcdirmid 9y agoC# has reified generics, which solve a lot of problems that would otherwise be addressed with metaclasses. For example, factories can be setup quickly by reflection over a generic type variable.