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

Autoscoped constructors #9190

Merged
merged 29 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
3ac0f63
Autoscoped constructors
JaroslavTulach Feb 26, 2024
0342ce3
Applying two arguments
JaroslavTulach Feb 27, 2024
75aed7e
Currying of UnresolvedConstructor works
JaroslavTulach Feb 27, 2024
be51963
Reorder arguments by specifying their name
JaroslavTulach Feb 27, 2024
7bd5c4d
Testing defaulted arguments
JaroslavTulach Feb 27, 2024
8266b52
Autoscoping benchmark
JaroslavTulach Feb 27, 2024
774438c
Merge remote-tracking branch 'origin/develop' into wip/jtulach/Autosc…
JaroslavTulach Feb 29, 2024
f34d56b
Renaming to AutoscopedConstructorTest
JaroslavTulach Feb 29, 2024
6bcd8dc
Use SrcUtil.source to make sure IGV can find .enso source on disk
JaroslavTulach Feb 29, 2024
59fa776
Finish measurement after 1s when in bench.compileOnly=true mode
JaroslavTulach Feb 29, 2024
28b1679
Splitting benchmark code to multiple lines
JaroslavTulach Feb 29, 2024
5aa2699
Share a common Context builder setup for all benchmarks
JaroslavTulach Feb 29, 2024
f5a0c7f
250x times speedup with ConstructNode
JaroslavTulach Feb 29, 2024
d10fdb1
javafmtAll
JaroslavTulach Feb 29, 2024
2646b15
Constructor, two constructors and no suitable constructor test
JaroslavTulach Mar 1, 2024
6987672
Note in changelog
JaroslavTulach Mar 1, 2024
2b687f1
Check the whole error message
JaroslavTulach Mar 1, 2024
66e8f32
Choose first constructor
JaroslavTulach Mar 1, 2024
1d91c16
Back.Times constructor is selected
JaroslavTulach Mar 1, 2024
0c1aabf
Testing constructor with all defaulted arguments
JaroslavTulach Mar 1, 2024
a026086
Properly passing on caller's state when resolving UnresolvedConstructor
JaroslavTulach Mar 1, 2024
9c9dc13
How to materialize Vector elements with unresolved constructors
JaroslavTulach Mar 1, 2024
eb7b701
Fixing additionalDescriptions typo
JaroslavTulach Mar 1, 2024
49202c9
Better javadoc
JaroslavTulach Mar 1, 2024
463e33f
Done: Static Methods on Types, Unboxed Atoms, Unboxed Vectors, Parser
JaroslavTulach Mar 2, 2024
bc5c6fd
Documenting autoscoped constructors
JaroslavTulach Mar 4, 2024
6e32a3a
Better error message for autoscoped constructors
JaroslavTulach Mar 4, 2024
60bfc76
Avoid concatenation of strings on fast path
JaroslavTulach Mar 4, 2024
323f909
Type_Error.to_text = TypeError.to_display_text
JaroslavTulach Mar 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,7 @@
- [Add run_google_report method][8907]
- [Execute and debug individual Enso files in VSCode extension][8923]
- [Check type of `self` when calling a method using the static syntax][8867]
- [Autoscoped constructors][9190]

[3227]: https://github.com/enso-org/enso/pull/3227
[3248]: https://github.com/enso-org/enso/pull/3248
Expand Down Expand Up @@ -1209,6 +1210,7 @@
[8907]: https://github.com/enso-org/enso/pull/8907
[8923]: https://github.com/enso-org/enso/pull/8923
[8867]: https://github.com/enso-org/enso/pull/8867
[9190]: https://github.com/enso-org/enso/pull/9190

# Enso 2.0.0-alpha.18 (2021-10-12)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,15 @@ type Type_Error
_ -> ". Try to apply " + (missing_args.join ", ") + " arguments"
_ -> tpe.to_text

"Type error: expected "+self.comment+" to be "+self.expected.to_display_text+", but got "+(if type_of_actual.is_a Text then type_of_actual else "<ERR>")+"."
got = if type_of_actual.is_a Text then type_of_actual else "<ERR>"
exp = self.expected.to_display_text
msg = self.comment
. replace "{exp}" exp
. replace "{got}" got
"Type error: "+msg+"."

to_text : Text
to_text self = self.to_display_text

@Builtin_Type
type Compile_Error
Expand Down
68 changes: 7 additions & 61 deletions docs/runtime-roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,11 @@ priority, but the dependencies between tasks are described.

## Technology Choices

With the advent of Java 17 and its ergonomic improvements (read:
pattern-matching), it makes little sense to retain the usage of Scala throughout
the compiler. The language was originally introduced due to the capabilities of
its type system in comparison to Java's, but very little of this functionality
has been used in the end.

We recommend moving everything to Java as part of this work, as you will end up
with better tooling support. Scala has been a problem child.

Enso originally started working with Java 8, and was transitioned (painfully,
due to the JPMS) to Java 11. Java 8 was EOL'd by the graal team after a couple
of years. It seems likely that Java 11 will suffer a similar fate, though the
transition from 11 to 17 will be far less painful as it doesn't introduce any
breaking language-level changes.
Enso interpreter is written in a mixture of Scala and Java. Scala was originally
used due to the capabilities of its type system in comparison to Java's. Modern
Java (as provided by JDK 21 or [Frgaal compiler](http://frgaal.org)) meets most
of the needs too. The ultimate goal is to write everything in Java and also keep
up with most recent long term supported JDK/GraalVM releases.

## Static Analysis

Expand All @@ -49,7 +40,8 @@ Currently, the IR is:
- Very verbose and difficult to add a new node to. Adding a new node requires
adding ~100 lines of code that could likely be automated away. Lots of
boilerplate.
- Of unknown performance.
- Of poor performance as witnessed by
[static compiler benchmarks](https://github.com/enso-org/enso/pull/9158)
- Partially mutable, making it confusing as to which things are shared.

A new IR for Enso would have to:
Expand Down Expand Up @@ -252,25 +244,6 @@ To rectify this situation, we recommend implementing a system we have termed
With this done, it may still be necessary to create a Java DSL for implementing
built-in methods and types, but that is unclear at this point.

### Static Methods on Types

Currently, Enso allows calling methods on _modules_, _constructors_, and
_instances_. This does not conform to the language specification because it
allows constructors and instances to be treated the same at runtime. This leads
to odd results (see the ticket below).

The end result should be compliant with the design described
[here](https://github.com/enso-org/enso/issues/1851), and needs to be taken into
account when defining builtins.

### Better Safepointing

Enso currently uses a hand-rolled safepointing system for interrupting threads
and handling resource finalisation. With 21.1, Truffle landed its own system for
doing this. Enso should be updated to use
[the new system](https://github.com/oracle/graal/blob/master/truffle/docs/Safepoints.md),
instead, as it will provide better performance and more robust operation.

## Runtime Performance

While Enso is performant when it gets JITted by GraalVM, the performance when
Expand All @@ -290,29 +263,6 @@ This can be greatly improved.
be improved.
- Many of the above-listed static optimisations will greatly help here.

### Unboxed Atoms

Currently every atom in Enso is stored boxed. In limited circumstances it may be
possible to unbox these and hence remove the indirection cost when accessing
their data.

- Read the details of Truffle's
[`DynamicObject`](https://www.graalvm.org/truffle/javadoc/com/oracle/truffle/api/object/DynamicObject.html),
and the sources.
- Use this system to inform the design for a system that reduces the overhead of
dynamic field names and arities when accessing data on Atoms.

### Unboxed Vectors

Enso currently doesn't have support for unboxed arrays (and hence vectors). This
means that it incurs a significant performance cost when working with pure
numerical arrays. This can be improved.

- Read the truffle documentation on
[truffle libraries](https://github.com/oracle/graal/blob/master/truffle/docs/TruffleLibraries.md).
- Based on this, define a system that seamlessly specializes and deoptimises
between boxed and unboxed arrays as necessary.

## IDE

As Enso's primary mode of use is in the IDE, there are a number of important
Expand Down Expand Up @@ -362,7 +312,3 @@ preprocessors.
- Implement caching support for the visualization expression processing.
- This cache should, much like the IDE's introspection cache, track and save the
values of all top-level bindings in the visualization preprocessor.

## Parser

Parser
12 changes: 6 additions & 6 deletions docs/syntax/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ binds the function name. This means that:
user-defined type for the function.

```ruby
sum : (a: Monoid) -> a -> a
sum : (a:Monoid) -> a -> a
sum : x -> y -> x + y
sum x y = x + y
```
Expand All @@ -113,19 +113,19 @@ Methods can be defined in Enso in two ways:
```ruby
type Maybe a
Nothing
type Just (value : a)
Just (value : a)

isJust = case this of
Nothing -> False
Just _ -> True
is_just self = case self of
Maybe.Nothing -> False
Maybe.Just _ -> True
```

2. **As an Extension Method:** A function defined _explicitly_ on an atom counts
as an extension method on that atom. It can be defined on a typeset to apply
to all the atoms within that typeset.

```ruby
Number.floor = case this of
Number.floor self = case self of
Integer -> ...
...
```
Expand Down
48 changes: 32 additions & 16 deletions docs/syntax/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,32 +276,48 @@ context-dependent manner that is discussed properly in the
[type system design document](../types/README.md), but is summarised briefly
below.

- **Name and Fields:** When you provide the keyword with only a name and some
field names, this creates an atom.

```ruby
type Just value
```

- **Body with Atom Definitions:** If you provide a body with atom definitions,
this defines a smart constructor that defines the atoms and related functions
by returning a typeset.

```ruby
type Maybe a
type Maybe
Nothing
type Just (value : a)
Just (value : Integer)

is_just self = case self of
Maybe.Nothing -> False
Maybe.Just _ -> True

nothing self = self.is_just.not
```

isJust = case this of
Nothing -> False
Just _ -> True
To reference atoms use type name followed by the name of the atom. E.g.
`Maybe.Nothing` or `Maybe.Just 2`. Atom constructors act like functions and
fully support currying - e.g. one can create `fn = Maybe.Just` and later apply
two to it (`fn 2`) to obtain new atom.

nothing = not isJust
- **Autoscoped Constructors:** Referencing constructors via their type name may
Copy link
Member Author

Choose a reason for hiding this comment

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

Documenting autoscoped constructors is hard when most of the surrounding documentation is outdated...

lead to long and boilerplate code. To simplify referencing constructors when
the _context is known_ a special `~` syntax is supported. Should there be a
method `describe`:

```ruby
describe (m : Maybe) -> Text = if m.is_just then m.value.to_text else "Empty"
```

one may invoke it as `describe (Maybe.Just 5)` - e.g. the regular way. Or one
may use _autoscoped constructors_ and call

```ruby
describe (~Just 5)
```

Please note that the `type Foo (a : t)` is syntax only allowable inside a type
definition. It defines an atom `Foo`, but constrains the type variable of the
atom _in this usage_.
the argument `(~Just 5)` is _recorded but not executed_ until it is send to
the `describe` method. The argument of the `describe` method is known to be of
type `Maybe` and have `Just` constructor. The _scope_ is now known and the so
far deferred `~` value gets evaluated. `Maybe.Just 5` atom is constructed and
execution of `describe` method continues with such atom.

- **Body Without Atom Definitions:** If you provide a body and do not define any
atoms within it, this creates an interface that asserts no atoms as part of
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package org.enso.interpreter.bench.benchmarks.semantic;

import java.nio.file.Paths;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.logging.Level;
import org.enso.polyglot.RuntimeOptions;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.io.IOAccess;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.BenchmarkParams;
import org.openjdk.jmh.infra.Blackhole;

Expand All @@ -33,16 +36,7 @@ public class ArrayProxyBenchmarks {

@Setup
public void initializeBenchmark(BenchmarkParams params) throws Exception {
Engine eng =
Engine.newBuilder()
.allowExperimentalOptions(true)
.option(RuntimeOptions.LOG_LEVEL, Level.WARNING.getName())
.logHandler(System.err)
.option(
"enso.languageHomeOverride",
Paths.get("../../distribution/component").toFile().getAbsolutePath())
.build();
var ctx = Context.newBuilder().engine(eng).allowIO(IOAccess.ALL).allowAllAccess(true).build();
var ctx = SrcUtil.newContextBuilder().build();
var code =
"""
import Standard.Base.Data.Vector.Vector
Expand Down
Loading
Loading