Some PygeonJava rules
February 25, 2007 – 4:57 amIn previous posts, I introduced the idea of an alternative syntax for Java designed for educational purposes, which I’m calling PygeonJava. The design is still in progress, but here are some tentative ideas, most of them attempts at reducing learner confusion about the resolving of named things (i.e. identifying what identifiers refer to).
- Each part of a package name ends in /, e.g. java.lang is written java/lang/ . This makes packages easy to distinguish from object references and type names.
- No static imports.
- No default package. All files must declare their allegiance to a package.
- No default access.
- Importing multiple types of the same name causes a conversion error (the program that translates PygeonJava to Java I’m calling a ‘converter’). To get around this problem, fully qualify the types you need in the code with the full package name, e.g. java/io/File.
- Similarly, it is not allowed to import a type of the same name as a type in the current package.
- Types in java.lang are not automatically imported, even Object. (Is this extreme? Certainly, but it means learners can use a consistent process when they see a capitalized process and want to know where it comes from: if it’s not qualified by its package name and its not in the import list, then it must be in the current file or at least the same package.)
- In the spirit of explicitness, all calls to the super constructor should be required to be explicit, so you’ll always see super() (or some overloaded variant thereof) as the first line in a constructor, even for a class extending Object.
- Also in the spirit of explicitness, a class should be required to include at least one constructor, even if it’s just a ‘default’ constructor with nothing but a call to super().
- All uses of instance fields and methods of the current class must be qualified by ‘this’—except instead of using the word ‘this’, ‘me’ is used instead (mostly because it is shorter but also because I remember finding the semantics of ‘this’ strangely confusing). The problem I mean for this to solve is confusion in distinguishing locals from members and rules about name collisions. Arguably, methods need not be qualified explicitly by ‘me’, but I think it’s more consistent to require it.
- A concern is that static members are not really part of an object, so referencing statics via object references rather than explicitly via the type name seems wrong because the object is not really being used except as a representative of its type. The stringent thing to do would be to require all references to statics to be done via their type name, not via instances or with the ‘me’ reference.
This comes very close to covering all cases, but it’s possible in foo.bar() that foo could refer to a thing of type X or a descendant of type X, and static method bar could have been overridden in the descendant of X. I don’t really see a solution, and I’ll just have to accept this Javaism. I think it’s sensible to advise users to reference statics via the type name as much as possible, especially in favor of referencing them via ‘me’.Seems I was wrong: statics are resolved always at compile time using the type of the reference, not at runtime using the actual type of the object referenced. So it actually is a good idea to require all statics to be referenced via the type name. Unless I’m overlooking something, I guess the reason Java doesn’t have this rule is because it was considered inconvenient. - Similarly, inherited members are accessed only via ’super’, not ‘me’. This eliminates another arbitrary choice for learners, reinforces the concept, and reminds learners where the member comes from.
- Initialization sections can be simply omitted from PygeonJava, and I’m thinking the same about field initializations. It’s generally a bad idea to write code that relies upon subtleties of the language that few of its practitioners understand, and I feel the execution order rules concerning field initializations, initialization sections, and constructors fall into this category. Better to just eliminate the whole question.
- A class file has this enforced order: static fields, then instance fields, then constructors, then instance methods, then static methods (or maybe static methods before instance methods). This is essentially arbitrary, but it’s the most typical style I’ve encountered. (I haven’t decided whether to include named inner classes, but if so, they would go after everything else.)
- Allowing interfaces to include static final fields is quite confusing as it distracts from the main purpose of interfaces.
I’m beginning to reconsider what I said about Java not being as much in need of an alternative syntax as C. Sure, nothing is quite as glaringly flawed as C’s declaration syntax, but things add up, and I’m beginning to remember how confusing I found parts of the language when learning it.
I’m also beginning to realize that, rather than making my converter merely produce workable Java using one-to-one translations, it may need to do some semi-sophisticated analysis to enforce some of PygeonJava’s restrictions. Additionally, it’s quite important for the converter to give good error messages of its own because learners won’t be able to comprehend javac’s messages—professional Java programmers have a hard enough time understanding compiler messages, so I doubt students only familiar with an alternative syntax of the language would fare well.