Skip to content
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

Refactor an internal API system (part 1: new class system & remove all internal properties from DSL) #376

Open
wants to merge 25 commits into
base: main
Choose a base branch
from

Conversation

AndreiKingsley
Copy link
Collaborator

@AndreiKingsley AndreiKingsley commented Apr 25, 2024

This is the first part of several PRs with internal API redesigns. In this one, I reworked the class system used to build DSLs. The PR is big, but the minimum possible because it changes the root of the system.

What went into this PR

  • A new system of DSL interfaces and classes, most classes/properties are now internal
  • Implementations of these classes for Lets-Plot
    You can build api and lets-plot modules (and test them in a Kotlin Notebook, for example).

What is NOT included in this PR:

  • DatasetHandler is still unchanged
  • echarts module (only some rename was done)
  • Tests
    • I partially changed the tests in the api module to make them consistent with the new API, but a few did not make it yet - I commented them out; the tests in the api module are fully buildable and there're passed
    • In lets-plot the tests are not consistent
      • Statistics needs to be updated as well
  • Documentation

Fixes #163, fixes #378, fixes #379, fixes #380, fixes #381.

@AndreiKingsley AndreiKingsley added this to the Kandy release v0.7.0 milestone May 1, 2024
Copy link
Collaborator

@devcrocod devcrocod left a comment

Choose a reason for hiding this comment

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

I looked at the first part regarding the API

// must be LayerCreatorScope, marker of containing grouped data
// (needed for transformations, especially statistics)
public sealed interface GroupedDataScope<T, R> {
public val key: ColumnGroup<T>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Still don't like using the key( This is not obvious to many, including me

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's not an obligation, but a convenience. Sometimes it's important to perform mapping from a key, so if you write a key.column, you won't make a mistake.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

You can still write the same thing without the key
.

Copy link
Collaborator

Choose a reason for hiding this comment

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

In this case I get an exception of different column sizes

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Where?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This could be the case with stats because they don't currently provide context for the new dataframe - after these changes they will.

Copy link
Collaborator

Choose a reason for hiding this comment

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

This class and MultilayerPlotBuilder raised questions for me. Why SingleLayerPlotBuider is inherited from PlotBuilder?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

PlotBuilder has plot features regardless of whether the builder is a multi-layer, single-layer or any other type (for example build with series or any new way). For example - layout.

@@ -28,7 +29,8 @@ import org.jetbrains.kotlinx.kandy.ir.feature.PlotFeature
* }
* ```
*/
public fun PlotContext.coordFlip() {
public fun PlotBuilder.coordFlip() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

how many plot features do we have?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

potentially as many as we want (in fact as lets-plot has)

Copy link
Collaborator

Choose a reason for hiding this comment

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

It seems to me that all our features are mainly layer features, and we only have experimental features for plot

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Layout?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

And what's problem with plot features?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Not a problem, just a fact: the map of features is there, but the features are not

Copy link
Collaborator

@devcrocod devcrocod left a comment

Choose a reason for hiding this comment

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

It is necessary to write KDoc and check the current ones. Also, in abstract classes, you can use protected instead of internal, so that properties will be accessible in subclasses.

@AndreiKingsley
Copy link
Collaborator Author

In most cases, the properties need to be accessible outside of the class so they are made internal (i.e. actually public, but for modules, not to the user - what I called semi-internal)

@AndreiKingsley
Copy link
Collaborator Author

@devcrocod add ColumnsContainer to GroupedDataScope with last commit, check please

@@ -43,7 +46,8 @@ public inline fun PlotContext.layout(block: Layout.() -> Unit) {
* Accessor for the [Layout] of a plot.
* Returns an existing [Layout] if one exists, or creates a new one otherwise.
*/
public val PlotContext.layout: Layout
@Suppress("INVISIBLE_MEMBER")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do you think that if we have several suppresses, maybe it’s better to apply them to the entire file?

@@ -4,12 +4,14 @@

package org.jetbrains.kotlinx.kandy.letsplot.feature

import org.jetbrains.kotlinx.kandy.dsl.internal.PlotContext
import org.jetbrains.kotlinx.kandy.dsl.internal.MultiLayerPlotBuilder
Copy link
Collaborator

Choose a reason for hiding this comment

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

unused import
set import optimization on commit

import org.jetbrains.kotlinx.kandy.ir.feature.FeatureName
import org.jetbrains.kotlinx.kandy.ir.feature.PlotFeature
import org.jetbrains.kotlinx.kandy.letsplot.style.CustomStyle
import org.jetbrains.kotlinx.kandy.letsplot.style.Theme
import org.jetbrains.kotlinx.kandy.letsplot.style.Style
import org.jetbrains.kotlinx.kandy.dsl.internal.*
Copy link
Collaborator

Choose a reason for hiding this comment

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

set settings for specific import instead *

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

But then there would be a red highlighting

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

And I don't want to do auto-optimisation for the same reason

Copy link
Collaborator

Choose a reason for hiding this comment

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

image

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hm, I tried this before and it didn't work for me back then, but now it does.
Well, then we need to add this suppressing to almost every file.

@@ -13,31 +13,9 @@ import org.jetbrains.kotlinx.kandy.ir.aes.Aes
*
* @throws IllegalArgumentException If the provided aesthetic value is not within the specified range.
*/
public fun <T : Comparable<T>> checkInRange(aes: Aes, value: T, range: ClosedRange<T>): Unit =
@PublishedApi
internal fun <T : Comparable<T>> checkInRange(aes: Aes, value: T, range: ClosedRange<T>): Unit =
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we can make an extension function here:

public fun <T:  Comparable<T>> Aes.checkInRange(value: T, range: ClosedRange<T>): Unit

In this case, we can make it public, which will save us from having to suppress


/**
* Provides a constant setter for the `slope` value.
*
* @property slope A [ConstantSetter] object to directly set the slope.
*/
public val slope: ConstantSetter
get() = ConstantSetter(SLOPE, bindingCollector)
public val slope: org.jetbrains.kotlinx.kandy.letsplot.layers.builders.aes.ConstantSetter
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove qualifier name

public val xEnd: ConstantSetter
get() = ConstantSetter(X_END, bindingCollector)
public val xEnd: org.jetbrains.kotlinx.kandy.letsplot.layers.builders.aes.ConstantSetter
get() = org.jetbrains.kotlinx.kandy.letsplot.layers.builders.aes.ConstantSetter(
Copy link
Collaborator

Choose a reason for hiding this comment

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

remove qualifier name

datasetIndex: Int = parent.datasetIndex
) :
LayerBuilderImpl(parent, datasetIndex), ABLineBuilderInterface {
internal override val geom: Geom
Copy link
Collaborator

Choose a reason for hiding this comment

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

You can make geom and requiredAes as protected in LayerBuilderImpl

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