Paving the on-ramp

Brian Goetz brian.goetz at oracle.com
Thu Sep 29 01:36:45 UTC 2022



> A major design goal of yours seems clear: to get there without 
> rendering Java source files explicitly bimorphic ("class" source files 
> all look like this, "main" source files all look like that). Instead 
> you have a set of independent features that can compose to get you 
> there in a "smooth ramp". The design looks heavily influenced by that 
> goal.

Yes, I sometimes call this "telescoping", because there's a chain of "x 
is short for y is short for z".  For example, with lambdas:

     x -> e

is-short-for

     (x) -> e

is-short-for

     (var x) -> e

is-short-for

     (int x) -> e  // or whatever the arg is

As a design convention, it enables a mental model where there is really 
just one form, with varying things you could leave out. Early in the 
Lambda days, we saw articles like "there are N forms of lambda 
expressions", and that stuff infuriates me, it is as if people go out of 
their way to find more complex mental models than necessary.

> As my program grows and gets more complex, I will make changes like
>
> * use more other libraries
> * add args to main()
> * add helper methods
> * add constants
> * create new classes and use them from here
>
> But: when and why would I be motivated to change *this* code *itself* 
> to "become" a class, become instantiable, acquire instance state, etc. 
> etc.? I don't imagine ever having that urge. main() is just main()! 
> It's just a way in. Isn't it literally just a way to (a) transfer 
> control back and forth and (b) hand me args?

This doesn't seem like such a leap to me.  You might start out 
hardcoding a file path that will be read.  Then you might decide to let 
that be passed in (so you add the args parameter to main).  Then you 
might want to treat the filename to be read as a field so it can be 
shared across methods, so you turn it into a constructor parameter.  One 
could imagine "introduce X" refactorings to do all of these.  The 
process of hardcoding to main() parameter to constructor argument is a 
natural sedimentation of things finding their right level.  (And even if 
you don't do all of this, knowing that its an ordinary class (like an 
enum or a record) just with a concise syntax means you don't have to 
learn new concepts.  I don't want Foo classes and Bar classes.)

>
> Note I was only reacting to "static bad!" here. I would be happy if 
> *that* argument were dropped, but you do still have another valid 
> argument: that `static` is another backward default, and the viral 
> burden of putting it not just on main() but every helper method you 
> factor out is pure nuisance. (I'd suggest mentioning the viral nature 
> of this particular burden higher/more prominently in the doc, as it's 
> currently out of place under the "unnamed classes" section.)
>
> (That doesn't mean "so let's do it"; I still hope to see that benefit 
> carefully measured against the drawbacks. Btw, *some* of those 
> drawbacks might be eased by disallowing an explicit constructor... and 
> jeez, please disallow type parameters too... I'm leaving the exact 
> meaning of "disallow" undefined here.)

Indeed, I intend that there are no explicit constructors or instance 
initializers here.  (There can't be constructors, because the class is 
unnamed!)  I think I said somewhere "such classes can contain ..." and 
didn't list constructors, but I should have been more explicit.

>
>     ## Unnamed classes
>
>     In a simple program, the `class` declaration often doesn't help
>     either, because
>     other classes (if there are any) are not going to reference it by
>     name, and we
>     don't extend a superclass or implement any interfaces.
>
>
> How do I tell `java` which class file to load and call main() on? 
> Class name based on file name, I guess?

Sadly yes.  More sad stories coming on this front, Jim can tell.

>
>     If we say an "unnamed
>     class" consists of member declarations without a class header,
>     then our Hello
>     World program becomes:
>
>     ```
>     void main() {
>         System.out.println("Hello World");
>     }
>     ```
>
>
>
> One or more class annotations could appear below package/imports?

No package statement (unnamed classes live in the unnamed package), but 
imports are OK.  No class annotations.  No type variables.  No 
superclasses.

>     Such source files can still have fields, methods, and even nested
>     classes,
>
>
> Do those get compiled to real nested classes, nested inside an unnamed 
> class? So if I edit a "regular" `Foo.java` file, go down below the 
> last `}` and add a `main` function there, does that cause the whole 
> `Foo` class above to be reinterpreted as "nested inside an unnamed 
> class" instead of top-level?

To be discussed!

> This is my notion of a natural progression:
>
> 1. Write procedural code: calling static methods, using existing data 
> types, soon calling their instance methods
> 2. Proceed to creating your own types (from simple data types onward) 
> and using them too
> 3. One day learn that your main() function is actually a method of an 
> instantiable type too... at pub trivia night, then promptly forget it

Right.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-experts/attachments/20220928/f0539d6d/attachment-0001.htm>


More information about the amber-spec-experts mailing list