> From: "Brian Goetz" <[email protected]>
> To: "Remi Forax" <[email protected]>, "Ron Pressler" <[email protected]>
> Cc: "Dan Heidinga" <[email protected]>, "amber-spec-experts"
> <[email protected]>
> Sent: Monday, February 20, 2023 7:57:53 PM
> Subject: Re: Implicit Record Was: JEP draft: Implicit Classes and Enhanced
> Main
> Methods (Preview)
> So, I think you're bringing a mental model of "field" that might not be
> warranted.
> In the context of an implicit class, all the members are effectively private,
> because the class is synthetic and therefore ordinary code can't call the
> constructor, access static members, use the class literal Foo.class, etc. So
> the members of an unnamed class are accessible from the implicit class only,
> even if they are public (because the class name is a secret from everyone but
> the launcher.)
> So to that end, you can start by teaching about statements:
> System.out.println("Foo!")
> and that statements live in methods
> void main() {
> System.out.println("Foo!")
> }
> and that methods can call methods:
> void greet() {
> System.out.println("Foo!")
> }
> void main() {
> greet();
> }
> and that methods can access variables:
> int greetCount = 0;
> void greet() {
> System.out.println("Foo!");
> ++greetCount;
> }
> void main() {
> greet();
> greet();
> System.out.println(STR."Now I've said it \{greetCount} times");
> }
> From the perspective of a first-day student, the methods and variables are a
> sea
> of local members that can see each other.
> Then, the curtain is pulled back, to reveal that these variables and methods
> are
> actually instance members on some instance of some class, which can be given a
> name and operated on from the outside.
As i said earlier, it does not work because fields and local variables have
different semantics,
fields are initialized with a default value while local variables need to be
initialized before use.
So the curtain is just a veil that will be pierced by any students moving
declarations around.
>From my personal experience, unifying local variable and field leads to more
>pain than gain, mostly because local variables are not shared while fields
>are. And as an anecdote, i've added a slide in my latest Valhalla presentation
>re-explaining the difference between local variables and fields because i had
>too many basic questions when introducing the concepts of scalarization and
>flattening.
Rémi
> On 2/20/2023 7:08 AM, [ mailto:[email protected] | [email protected] ] wrote:
>>> From: "Ron Pressler" [ mailto:[email protected] |
>>> <[email protected]> ]
>>> To: "Remi Forax" [ mailto:[email protected] | <[email protected]> ]
>>> Cc: "Dan Heidinga" [ mailto:[email protected] | <[email protected]> ] ,
>>> "Brian Goetz" [ mailto:[email protected] | <[email protected]> ] ,
>>> "amber-spec-experts" [ mailto:[email protected] |
>>> <[email protected]> ]
>>> Sent: Monday, February 20, 2023 10:47:57 AM
>>> Subject: Re: Implicit Record Was: JEP draft: Implicit Classes and Enhanced
>>> Main
>>> Methods (Preview)
>>> I was trying to understand how you tie shared variables to encapsulation and
>>> what you meant by something that students later need to unlearn, and I
>>> think I
>>> understand now. You’re okay with shared mutable state as long as it’s clear
>>> that it’s not shared with the whole world but only with some explicit unit,
>>> and
>>> since an implicit class appears to be the whole world, then its fields seem
>>> to
>>> be globally shared, and that’s what you want to avoid your students
>>> learning.
>>> Is that correct?
>> yes. But it's one of the arguments.
>> The real problem is dangling fields. Conceptually fields are far more
>> "attached"
>> to a class than methods (at least until you explain classes) but
>> syntactically
>> with an implicit class, you do not see that. Allowing dangling fields force
>> the
>> teacher to explain what an implicit class is which defeat the teaching
>> purpose
>> of it.
>>> Now, we’re not in the business of telling teachers how to teach, and I
>>> assume
>>> different teachers teach in different ways. Implicit classes are not
>>> exclusively a teaching construct, but a natural Java construct — a natural
>>> extension of implicit modules and packages.
>> Agree, but there are some fundamentals, introducing fields without the
>> notion of
>> class is hard to envision.
>>> Expert programmers may also appreciate implicit classes just as they
>>> appreciate
>>> JShell and launching source-code programs, both of which are also explicitly
>>> motivated, at least in part, by education (see JEPs 222 and 330).
>> yes,
>> Here we are discussing about ergonomics, i.e. is the "natural" extension is
>> implicit class or implicit record ?
>> With JEP 330, it's fear easier to create one file scripts written in Java
>> instead of Python mostly because Python on Windows does not work as well as
>> Python on Linux. I've seen several of those scripts on github, and there are
>> not all using "class" as the top-level containers, some are using
>> "interface",
>> i've not seen a lot of scripts using records but record is a more novel
>> construct. Implicit class is not necessary the right default.
>>> That natural Java construct *allows* teachers to teach in the order and
>>> style
>>> they choose without *forcing* classes on them. Some teachers may teach just
>>> basic control flow and (local) variables, perhaps records, and treat List,
>>> Map,
>>> and Set as built-in constructs without teaching any OOP in the first course
>>> and
>>> without teaching students how they can implement their own Lists etc. Some
>>> may
>>> choose to show shared variables (even if only to demonstrate their danger)
>>> while some may choose not to, although I assume everyone will teach
>>> constants.
>>> If you want to teach mutable fields only after introducing classes, that’s
>>> great and you can certainly do that (perhaps while enjoying the enhanced
>>> main
>>> and postponing static). But I don’t think the language should enforce a
>>> particular teaching style, where shared mutable state *must* be taught only
>>> in
>>> the context of classes. Even if you believe that doing otherwise is bad
>>> pedagogy, there is nothing that fundamentally ties shared variables to the
>>> ability to create class instances.
>> Agree, i'm not suggesting that there is a right way to teach, i'm too old for
>> that :)
>> Before implicit class, introducing field declarations without classes is not
>> something that was possible, so dangling fields is a new feature. As a
>> teacher,
>> the main reason to not allow dangling fields is that it creates confusion
>> between local variables and fields which is a real issue students wrestle
>> with.
>> Also, as a side remark, implicit class/record also creates new challenges
>> from
>> the teaching perspective, by example, you have to postpone explaining static
>> quite a bit otherwise if you explain that main() can be a static method too
>> soon, students will call you because this kind of code does not work
>> static void main() {
>> var color = new Color("blue"); // oops
>> }
>> class Color(String name) {
>> ...
>> }
>> My point is that while i agree that having an implicit container is a good
>> idea,
>> it does not make necessarily teaching easier, because an implicit container
>> is
>> a new feature that may interact badly with the rest of the features you want
>> to
>> teach.
>>> It’s true that we don’t want to cause harm by letting beginners learn
>>> something
>>> that needs to later be unlearned, but that’s not the case even for those
>>> who do
>>> learn about mutable fields. If students begin with implicit classes and
>>> seem to
>>> think that fields (if taught them) — or methods for that matter — are shared
>>> with the whole world, they invariably later learn that their “whole world”
>>> is
>>> actually a unit and that big programs are made by composing such units. They
>>> inevitably learn that because Java offers no other way. They *can’t* create
>>> a
>>> global variable, nor a global method, because Java simply doesn’t have
>>> those.
>>> Even if Java were to someday acquire package-level fields and methods (or
>>> even,
>>> hypothetically, module-level methods and fields), it still wouldn’t have a
>>> global namespace (not even for classes!). Learning that basic fact doesn’t
>>> require any unlearning, just contextualising.
>> Everything is encapsulated in Java, but dangling fields syntactically does
>> not
>> show that, that the issue.
>>> So we're giving teachers more freedom than ever before to teach Java in the
>>> manner each of them chooses, and I don’t think we’re inflicting any harm in
>>> the
>>> process. I think that restricting the abilities of implicit classes further
>>> forces a particular teaching style — though some may consider it the only
>>> correct style — and would also be a less natural Java construct and a less
>>> enjoyable one for experienced programmers.
>> The point is to teach Java, not to have to teach yet another new feature.
>> Offering new freedom also implies introducing new complexity.
>>> — Ron
>> Rémi
>>>> On 18 Feb 2023, at 07:11, [ mailto:[email protected] |
>>>> [email protected] ] wrote:
>>>> yes.
>>>> from my experience, the time to introduce the notion of class is when you
>>>> start
>>>> to have shared mutable state. What i do not like with the implicit class
>>>> proposal is the fact that you can have fields without defining the class
>>>> around.
>>>> But i think there is a solution.
>>>> What about the feature being renamed to "implicit record" instead of
>>>> "implicit
>>>> class" ? We have no discuss why the container of an implicit "class" has
>>>> to be
>>>> a class instead of an annotation, an interface, an enum or a record.
>>>> Having the container to be an annotation is useless given that an
>>>> annotation can
>>>> not have a main.
>>>> If the container is an interface, methods are abstract by default which is
>>>> not
>>>> what we want.
>>>> If the container is an enum, then we are closer to the idea of Ron that it
>>>> is a
>>>> singleton, especially if the container defined one implicit enum member
>>>> like
>>>> "SINGLETON" . An enum can not be inherited and the default constructor is
>>>> private which is are nice properties.
>>>> if the container is a record with no component, it can not be inherited,
>>>> the
>>>> constructor is package visible and more importantly to me, a user can not
>>>> defined instance fields ...
>>>> I prefer implicit record to implicit class because with a record as
>>>> container
>>>> you can not introduce a shared mutable state by error, you have at least to
>>>> write static in front of the field.
>>>> I dread about students being able to write code like this
>>>> String name;
>>>> void setName(String name) { this.name = name; }
>>>> void hello() { System.out.println(name); }
>>>> void main() {
>>>> setName("Bob");
>>>> ...
>>>> hello();
>>>> }
>>>> i.e to be able to declare mutable shared state without a class around (@Ron
>>>> without class encapsulation).
>>>> At least if the container is a record, "name" in the example above has to
>>>> be
>>>> static, from the student POV, an unusual variable.
>>>> An implicit record has also the advantage that you do not have to
>>>> introduce the
>>>> notion of class to explain the notion of implicit container, given that
>>>> records
>>>> are far simpler at the beginning than class, having the implicit container
>>>> being a record make sense because it's records all the way down.
>>>> What do you think about having the implicit container being a record
>>>> instead of
>>>> a class ?