Skip to content

update: improve Classes page #4786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open

Conversation

AlejandraPedroza
Copy link
Contributor

@AlejandraPedroza AlejandraPedroza commented Apr 2, 2025

This PR revamps the content and code examples in the Classes page following external feedback.
Some of the key changes are:

  • Improve the whole page and revamp the code snippets.

  • Explain the use case for multiple init blocks.

  • Explain constructor chaining.

  • Add examples for primary constructors.

  • Clarify the open keyword.

  • Explain how to access a class property from a class member function.

  • Use the term "object" consistently.

  • Clarify what abstract classes are.

  • Provide example companion objects.

@AlejandraPedroza AlejandraPedroza requested a review from a team as a code owner April 2, 2025 14:13
Copy link

@ice-phoenix ice-phoenix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My main question is: what are the things we want the reader to know, after they've finished reading the updated "Classes" page? Is it basic syntax for classes, details about constructors, details about initialization, smth else? Right now the section is a bit all over the place, I feel.

In other words, when we set to improve the page, what did we want to achieve?


Even more specifically, if you declare a [companion object](object-declarations.md#companion-objects) inside your class,
If you need to write a function that can be called without having a class object but still needs access
to the internals of the class, you can define it inside `companion object` within that class:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you define "internals of the class" here? A companion object can access its own internals, but class itself does not have any internals until you have created an instance of it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, here the terminology begins being a bit confusing, as "class object" and "companion object" look very similar, but mean significantly different things

Copy link
Contributor Author

@AlejandraPedroza AlejandraPedroza Apr 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you define "internals of the class" here?

This comes in the current version of the docs and I didn't modify it, but I rephrased it. What do you think?

Copy link

@ice-phoenix ice-phoenix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates! In general, I like the new version.

I narrowed down my main concern to the struggle between "being succinct and to the point targeting existing developers" in the old version vs "being very detailed and explaining very basic things targeting novice developers" in the new one. I don't know how to find a good balance here besides taking a look at the actual feedback of users and what they are missing.

Additionally, I think it's important to remember that, while all and every feedback is important, a lot of people who were completely satisfied with the current succinct and to-the-point version didn't leave their positive feedback. We might "over-optimize" for the smaller part of our target audience which is more vocal and more novice, and they want very basic things explained in detail.

Note: feel free to disregard my general feedback and only incorporate the technical notes, as you are the person who definitely knows more about how to write good technical documentation. If you believe it should be done in a specific way, then that's what we should do.

## Open keyword

In Kotlin, the `open` keyword indicates that a class or a member (function or property) can be overridden in subclasses.
By default, Kotlin classes and their members are _final_, meaning they cannot be inherited or overridden unless explicitly marked as `open`:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
By default, Kotlin classes and their members are _final_, meaning they cannot be inherited or overridden unless explicitly marked as `open`:
By default, Kotlin classes and their members are _final_, meaning they cannot be inherited from (for classes) or overridden (for members) unless explicitly marked as `open`:

}
```

In addition, you need to add the `open` keyword to every property

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this say exactly the same thing as in the previous paragraph?

unless explicitly marked as open

for reusable, structured code.

Classes are blueprints or templates for objects, which you
create via [constructors](#constructors-and-initializer-blocks). When you [create an instance of a class](#creating-objects-of-classes), you are creating

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for my education, how did you decide on which term to use: "instance", "object", "value", smth else? In the updated version you went with "object", I'm curious as to what were the reasons.

In this example, the `Person` class is defined with a primary constructor that declares a read-only property
`name` of type `String`. In the body, the class includes a mutable `age` property initialized to `0`.

This class represents a person with a fixed name and an age you can update after

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is one of the things I'm uncertain about. The old version of this page was not trying to explain the examples and the code to such detail, I believe it assumed some existing knowledge from the reader. Here we are explaining very basic things, meaning that we are targeting a very novice developer as our reader.

What is the expected "profile" of our main reader here?


## Constructors
To create an object of a class,
you must provide arguments for the constructor parameters. For more details, see the section [Creating objects of classes](#creating-objects-of-classes).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
you must provide arguments for the constructor parameters. For more details, see the section [Creating objects of classes](#creating-objects-of-classes).
you call one of its constructors and provide arguments for the constructor parameters. For more details, see the section [Creating objects of classes](#creating-objects-of-classes).

An abstract class can have both abstract and non-abstract members (properties and functions).
To declare a member as abstract, you must use the `abstract` keyword explicitly.

Abstract members do not have an implementation in the abstract class. The `override`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should add a sentence about how one provides an implementation by writing an override in an inheritor. That will also bridge us to the override keyword which is used for overrides.

val name: String,
val age: Int
) {
// Abstract member (doesn't provide default implementation, must be implemented by subclasses)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Abstract member (doesn't provide default implementation, must be implemented by subclasses)
// Abstract member (doesn't provide implementation, must be implemented by subclasses)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit more precise to talk about base (not default) implementations, as "default" term is already used in Kotlin for other things.

// Abstract member (doesn't provide default implementation, must be implemented by subclasses)
abstract fun introduce()

// Non-abstract member (has a default implementation)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Non-abstract member (has a default implementation)
// Non-abstract member (has an implementation)

that allows you to access its members using the class name without needing an object from the class.

If you need to write a function that can be called without creating an object of a class but still needs access to the
class's companion object members, you can define it inside an [object declaration](object-declarations.md) within the class:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class's companion object members, you can define it inside an [object declaration](object-declarations.md) within the class:
class's companion object members, you can define it inside an companion [object declaration](object-declarations.md) within the class:

In Kotlin, a [companion object](object-declarations.md#companion-objects) is a type of object declaration
that allows you to access its members using the class name without needing an object from the class.

If you need to write a function that can be called without creating an object of a class but still needs access to the

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rephrase this to smth like "If you need to write a function that can be called without creating an object of a class but is still logically connected to the class (such as a factory function), you can define ..."

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants