Skip to end of metadata
Go to start of metadata

At present, Groovy continues the Java and C++ tradition of treating classes as non-objects. This tradition is evidenced by the operators "new" and "instanceof", both of which imply that classes are not objects.

Of these, "new" is the most heinous crime against dynamic typing (not to mention good OO design), as it forces the specific type returned to be the general type requested. Further, it makes the caller responsible for allocation policies about which the class may have better ideas.

I think Groovy needs to implement a real OO allocation system, accessed by static methods. A default implementation of new() would be provided on Object, but if new() was defined explicitly, we would respect whatever visibility marker was specified. (This will all require some behind-the-scenes trickery, of course.) We would then eliminate the "new" keyword entirely.

This is a significant break with Java, for sure. But it simplifies the conceptual model of the language by making allocation just another operation, and by helping to move classes up to first-class objects. It also eliminates an entire series of constructs from the language. It would require that all classes be named (anonymous classes would go away in favour of named method-local classes), but this would only further simplify the language, as it means that all classes would be defined the same way, regardless of location.

There are some rough spots, of course. Visibility on constructors would be hard to enforce if all construction is done from within the class (ie. by new()), for instance. Also, the means by which a user-defined new() gets the allocation done on its behalf will likely involve compiler-supplied routines, or direct use of the reflection APIs.

But perhaps the biggest problem for this change (and quite likely its killer) will be community acceptance. A lack thereof. As much as it simplifies the language, it's not Java. At the very least, I would like to see us implement James's plan of allowing the "new" operator to be overloaded at the class level, so that we at least gain the benefits of decoupling allocation policy from the request.

– Chris Poirier

  • No labels

4 Comments

  1. Chris, I like this idea, as I also despise having to use the new statement. So are you suggesting something this:

    x = MyClass.new() ??

    So that the new is actually an operation on the class which returns an instance of itself?

    We could even take it a step farther:

    x = MyClass()

    Just like we have a similar shortcut to closure's call() method, we could offer this shortcut to the new() method. But this may be too ambiguous that we are actually allocating a new object unless you are aware that "MyClass" is a class.

    Either way, I don't think this idea would get a cold reception. I love Java's power and deep library of APIs, however I am no fan of its verbose and clunky syntax. Any attempts to improve the language should always merit some discussion.

  2. As much as I think I like the concept here, I suspect most people don't despise the "new" statement - I think you might be right Chris in your analysis of likely community acceptance. It's a difficult compromise isn't it.

    I've been thinking a little about how variants of this would impact developers who were using code they weren't particularly familar with. Keeping with the "new" keyword, but then allowing its actual behaviour to be overridden by MyClass.new() - does this conflict with the principle of lease surprise? In particular, would people less familiar with the language run into trouble if they always assumed "new" meant new? (I can just imagine the reaction of a few of my more cynical friends when they realised some bizarre behaviour they were seeing was because when it said new it didn't mean it...)

    Something that comes to mind is Java's String intern()ing, which doesn't really cause any trouble because Strings are immutable. And maybe people are straightforward enough not to override the default behaviour when the client might assume they have a dedicated instance of the class they can modify as they like. Sorry if that's not particularly well explained - I guess I'm trying to say that I'm not convinced that the compromise position is great.

    BTW, something to bear in mind if something like this is done - naming the method "new()" (as, IIRC, was one of the suggested options where this came up before) when it doesn't necessarily create a new object might not be the best idea for clarity. Don't really have better idea though (wink) - to list the obvious, some options are build, create, factory, construct, etc.

  3. Hi John,

    Yes, I was thinking of something like:

    But, there are significant complications actually making this work. It means that the compiler has to supply routines under the covers to do the actual allocation and constructor calls. That's not too much of a biggy. But the language would probably also have to supply some shorthand for linking method calls to constructors, and enforcing the visibility. It gets a little messy.

    OTOH, the newInstance() catch-all, that could intercept calls to "new", may have problems when the "new" expression is done in Java. I'm not too clear on if "new" uses the reflection interfaces or not. If so, it should be possible to cover Java, as well. In not, the scheme might only work from Groovy, and that would not be good.

  4. Java programmers are used to hew MyClass(a,b). The main constraint that puts on Groovy is a sort of backward compatibility, that most cut-n-paste 'new' expressions from Java should just work. However, Groovy gets much of its power from internal regularity, so making classes be values and having object allocation happen through regular methods is desirable. This says to me that the Java 'new' syntax should be defined, in Groovy, in terms of some sort of built-in static method. The power comes from the possibility of cutting in new functionality on the meta-method. (For example, some object systems treat 'newInstance' as a generic factory, which is allowed to take its arguments into account when choosing the exact implementation subclass; this is how mixins work in some Lisp object systems.)

    Concretely:

    Note that calling a static method through a Class object requires a dispatch step which is foreign to Java but natural in Groovy. If MyClass defines a static newInstance method, we should let it override the non-static Class.newInstance method. This point deserves more scrutiny, as dispatching methods on Class.

    So, I recommend investing carefully in the classes are always objects philosophy, working out the implications, and then using that framework to build the Groovy-native definition of 'new'.

    I also suggest a default Groovy method 'make' on Class which turns around and calls 'newInstance'. That would be the preferred factory method for APIs. If we decide interned strings are a really good convention to encourage (which they probably are), String.make would call String.intern, not Class.newInstance.