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

Implement hasLanguage interop message for all enso objects #11538

Merged
merged 29 commits into from
Nov 20, 2024

Conversation

Akirathan
Copy link
Member

@Akirathan Akirathan commented Nov 12, 2024

Blocks #11468

Pull Request Description

This PR implements the Truffle contract that all the Enso objects must export hasLanguage and getLanguage messages. By refactoring EnsoObject from an interface to an abstract class.

Important Notes

Checklist

Please ensure that the following checklist has been satisfied before submitting the PR:

  • Run engine and stdlib benchmarks
  • The documentation has been updated, if necessary.
  • Screenshots/screencasts have been attached, if there are any visual changes. For interactive or animated visual changes, a screencast is preferred.
  • All code follows the
    Scala,
    Java,
    TypeScript,
    and
    Rust
    style guides. In case you are using a language not listed above, follow the Rust style guide.
  • Unit tests have been written where possible.
  • If meaningful changes were made to logic or tests affecting Enso Cloud integration in the libraries,
    or the Snowflake database integration, a run of the Extra Tests has been scheduled.
    • If applicable, it is suggested to paste a link to a successful run of the Extra Tests.

@Akirathan Akirathan added CI: No changelog needed Do not require a changelog entry for this PR. CI: Clean build required CI runners will be cleaned before and after this PR is built. labels Nov 12, 2024
@Akirathan Akirathan self-assigned this Nov 12, 2024
@JaroslavTulach
Copy link
Member

Quick note: I believe there are other ways to enforce the contract while keeping EnsoObject an interface.

@Akirathan Akirathan changed the title Convert EnsoObject to abstract class Implement hasLanguage interop message for all enso objects Nov 13, 2024
@Akirathan Akirathan changed the title Implement hasLanguage interop message for all enso objects Implement hasLanguage interop message for all enso objects Nov 13, 2024
@Akirathan
Copy link
Member Author

An approach with leaving EnsoObject as interfce, and defining a separate class LanguageForEnsoObject with @ExportLibrary(value = InteropLibrary.class, receiverType = EnsoObject.class) does not work:

diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoObject.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoObject.java
index ce60158116..eb65b641b2 100644
--- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoObject.java
+++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/EnsoObject.java
@@ -1,6 +1,15 @@
 package org.enso.interpreter.runtime.data;

 import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.library.DynamicDispatchLibrary;
+import com.oracle.truffle.api.library.ExportLibrary;
+import com.oracle.truffle.api.library.ExportMessage;

 /** All non-primitive Enso types extends from {@code EnsoObject}. */
-public interface EnsoObject extends TruffleObject {}
+@ExportLibrary(DynamicDispatchLibrary.class)
+public interface EnsoObject extends TruffleObject {
+  @ExportMessage
+  Class<?> dispatch() {
+    return LanguageForEnsoObject.class;
+  }
+}
diff --git a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/LanguageForEnsoObject.java b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/LanguageForEnsoObject.java
index cfd3eda4c0..6114f01e0e 100644
--- a/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/LanguageForEnsoObject.java
+++ b/engine/runtime/src/main/java/org/enso/interpreter/runtime/data/LanguageForEnsoObject.java
@@ -1,8 +1,10 @@
 package org.enso.interpreter.runtime.data;

+import com.oracle.truffle.api.interop.InteropLibrary;
+import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.library.ExportLibrary;

-@ExportLibrary()
-public final class LanguageForEnsoObject {
-
+@ExportLibrary(value = InteropLibrary.class, receiverType = EnsoObject.class)
+public final class LanguageForEnsoObject implements TruffleObject {
+  // TODO: Export hasLanguage and getLanguage methods
 }

This patch fails to compile because Truffle DSL processor fails with errror: "@ExportLibrary is not supported for interfaces". And the receiver type must export DynamicDispatchLibrary.

TL;DR; EnsoObject cannot stay as an interface.

With the exception of toDisplayString message.
It is not automatically delegated because it is implemented in the super type.
@Akirathan Akirathan marked this pull request as ready for review November 14, 2024 17:57
/**
* Primitive values and exceptions currently don't have an associated language.
*
* <p>TODO[PM]: Will be implemented in https://github.com/enso-org/enso/pull/11468
Copy link
Member

Choose a reason for hiding this comment

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

How do you want to associate a language with java.lang.Long or java.lang.Boolean? What language you'd like to associate with such values? JavaScript? Enso?

Language can only be associated with Enso objects - e.g. subtypes of EnsoObject!

Copy link
Member Author

Choose a reason for hiding this comment

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

How do you want to associate a language with java.lang.Long or java.lang.Boolean? What language you'd like to associate with such values? JavaScript? Enso?

Literal 42 in Enso is really not a literal, it is an atom of type Integer. So you can, e.g., call 42.up_to 80 . each .... The same is true for True, which is not the same as java.lang.Boolean. In the comment, I am talking about Enso "primitives" and not Java primitives.

@JaroslavTulach
Copy link
Member

Quick note: I believe there are other ways to enforce the contract while keeping EnsoObject an interface.

I stay corrected. According to @chumer:

yes interfaces are deliberately not supported as interface checks are expensive.
Additionally they are a big pain to implement. (if not impossible)
...
My recommendation is to make EnseBaseObject an abstract base class. You can still keep your interface

Let's turn EnsoObject into abstract class and gain the speed!


@ExportMessage
@TruffleBoundary
public Object toDisplayString(boolean allowSideEffects) {
Copy link
Member

Choose a reason for hiding this comment

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

This method can be abstract. I suggest to make it abstract. Definitely don't delegate to toString() - that's just a way for the guest language hacker to gain too much information about Enso interpreter internals.

Copy link
Member Author

Choose a reason for hiding this comment

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

Refactored to abstract in 46ebbd3 . Note that it must be public, otherwise Truffle DSL errors with something like:

[error] /home/pavel/dev/enso/engine/runtime/src/main/java/org/enso/interpreter/runtime/warning/Warning.java:24:1:  error: Found invisible exported elements in super type 'EnsoObject': 
[error] public final class Warning extends EnsoObject {
[error]              ^     - org.enso.interpreter.runtime.data.EnsoObject.toDisplayString(boolean)
[error]   Increase their visibility to resolve this problem.

Copy link
Member

@JaroslavTulach JaroslavTulach left a comment

Choose a reason for hiding this comment

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

Turning EnsoObject into abstract class has a go!

@Akirathan
Copy link
Member Author

Akirathan commented Nov 18, 2024

Benchmarks scheduled:

GitHub
Enso Analytics is a self-service data prep and analysis platform designed for data teams. - Benchmark Engine · 6dd7ac5
GitHub
Enso Analytics is a self-service data prep and analysis platform designed for data teams. - Benchmark Standard Libraries · 6dd7ac5

@Akirathan
Copy link
Member Author

Akirathan commented Nov 19, 2024

stdlib benchmarks at https://github.com/enso-org/enso/actions/runs/11899829089 failed. Seems like a merge of newest develop will help here. Rescheduling benchmarks:

GitHub
Enso Analytics is a self-service data prep and analysis platform designed for data teams. - Benchmark Standard Libraries · 6dd7ac5
GitHub
Enso Analytics is a self-service data prep and analysis platform designed for data teams. - Benchmark Engine · 965f999
GitHub
Enso Analytics is a self-service data prep and analysis platform designed for data teams. - Benchmark Standard Libraries · 965f999

@Akirathan
Copy link
Member Author

Akirathan commented Nov 19, 2024

No regressions in benchmarks, the PR is ready to merge.

@jdunkerley jdunkerley merged commit 04075c5 into develop Nov 20, 2024
42 of 43 checks passed
@jdunkerley jdunkerley deleted the wip/akirathan/enso-object-abstract branch November 20, 2024 13:23
somebody1234 pushed a commit that referenced this pull request Nov 21, 2024
* EnsoObject is an abstract class, not an interface.

- Also, EnsoObject exports hasLanguage and getLanguage interop messages.
- BranchRecord converted to class

* Implement public getters in BranchResult

* Fix compilation of EnsoFile

* Add test that all enso values must have language

* Revert EnsoException - remove

* DataflowError and PanicException implement hasLanguage and getLanguage

* DataflowError is not EnsoObject - change signatures in some builtins

* Add more members to Module.isMemberInvocable.

Keep in sync with doInvoke.

* Revert "DataflowError and PanicException implement hasLanguage and getLanguage"

This reverts commit b30f396.

* Update the test - test only non-primitive and non-exception values

* Fix indexes in CodeLocationsTest

* Add more members to Function.isMemberInvocable

Keep in sync with doInvoke.

* EnsoObject.toDisplayString delegates to toString method

* EnsoObject.toDisplayString is behind TruffleBoundary

* Warning exports InteropLibrary which delegates to value.

With the exception of toDisplayString message.

* WithWarnings needs to explicitly export toDisplayString.

It is not automatically delegated because it is implemented in the super type.

* EnsoObject.toDisplayString just throws AssertionError

* AssertionError is behind TruffleBoundary

* Implement toDisplayString on some truffle objects

* Warning exports WarningsLibrary

* Revert "Warning exports WarningsLibrary"

This reverts commit a06c672.

* Add some warnings test

* Warning.isNull is always false

Even if it wraps Nothing

* Add some unnecessary methods to fix the compilation

* EnsoObject.toDisplayString is abstract

* ImportExportScope.toDisplayString is behind TruffleBoundary.

This fixes native-image build of engine-runner.

* Hide some toDisplayString methods behind TruffleBoundary

This fixes native-image build of engine-runner.
Bypassing failing test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: Clean build required CI runners will be cleaned before and after this PR is built. CI: No changelog needed Do not require a changelog entry for this PR.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants