Hacker News new | ask | show | jobs
by kazinator 3350 days ago
First 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.

1 comments

Yes, you're absolutely right that functions don't cover all use cases of factories. I was mostly thinking about the "why are there factories everywhere" complaint, which is mostly about factories that just produce one object.

> 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.

That seems like just one particular way to solve things. I guess I don't see what the fuss is about, if we are talking about metaclasses in particular, because we could also solve this problem with generics, and the factory solution doesn't seem that bad to begin with.

> Thus all constructors effectively have the same type signature.

Or turned around, the type system is not expressive enough to assign different types to different constructors, and is incapable of distinguishing them. This matches with my general experience, that metaclasses are useful on the dynamic typing side (Python, Lisp, Smalltalk, JavaScript) but annoying on the static typing side (C++, Haskell, C#).

But of course that makes sense. In a system without static types, the only way to pass a class to a function is through its parameters, so you have to pass the class by value. In systems with static typing, you have the additional option of passing a class through a type parameter, which has the advantage of giving you access to compile-time type checking. Furthermore, there are real theoretical problems with constructing type systems which allow you to use metaclasses involving whether the type checker is sound and whether it will terminate.