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

[RFC] Publish and Use: Elements and Libraries #476

Merged
merged 27 commits into from
Dec 6, 2023
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b2b734f
Add rfc for multi-file jayvee and scoping
georg-schwarz Aug 15, 2023
1ba5b87
Remove access of libraries to root level
georg-schwarz Nov 20, 2023
54aa967
Refactor import syntax according to review
georg-schwarz Nov 20, 2023
ba94e0b
Imports always refer a location (not necessarily a file)
georg-schwarz Nov 20, 2023
5d7e9c8
Library version numbers
georg-schwarz Nov 20, 2023
2d0e9e4
Distinguish file export and library
georg-schwarz Nov 21, 2023
db434a8
Change RFC 0015 status to discussion
georg-schwarz Nov 22, 2023
1e8d165
Fix formulations in RFC
georg-schwarz Nov 22, 2023
f62b807
Change keyword "export" to "publish" and adapt descriptions
georg-schwarz Nov 22, 2023
86d97bb
Rename "import" to "use" in RFC descriptions
georg-schwarz Nov 22, 2023
e71dea2
Add syntax to use all elements of a file
georg-schwarz Nov 22, 2023
96c241d
Remove version of libraries
georg-schwarz Nov 22, 2023
185ae1e
Describe viable locations for element usage
georg-schwarz Nov 22, 2023
a06ca37
Add library metadata as possible future enhancements
georg-schwarz Nov 22, 2023
df7e5a4
Switch around from and use in element imports
georg-schwarz Nov 22, 2023
67c8344
Add viable alternative publish syntax
georg-schwarz Nov 22, 2023
4110a4b
Change keyword "called" to "as"
georg-schwarz Dec 1, 2023
a628fed
Add explicit visibilities to RFC explanations
georg-schwarz Dec 1, 2023
0837c79
Add decision rationale section
georg-schwarz Dec 1, 2023
18ad295
Merge element visibility sections
georg-schwarz Dec 1, 2023
a230d63
Refactor concept "library" to concept "package"
georg-schwarz Dec 1, 2023
b578fef
Refactor scope levels and access paths
georg-schwarz Dec 4, 2023
f12e3fa
Improve RFC0015 wording at a few places
georg-schwarz Dec 4, 2023
cb8b061
Allow artificial namespaces when using all elements of a file
georg-schwarz Dec 4, 2023
5758e8b
Make scope level wording consistent
georg-schwarz Dec 4, 2023
3404302
Switch status of RFC0015 to "ACCEPTED"
georg-schwarz Dec 4, 2023
32d31a8
Clarify packages in packages visibility
georg-schwarz Dec 4, 2023
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
200 changes: 200 additions & 0 deletions rfc/0015-multi-file-jayvee/0015-multi-file-jayvee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
<!--
SPDX-FileCopyrightText: 2023 Friedrich-Alexander-Universitat Erlangen-Nurnberg
SPDX-License-Identifier: AGPL-3.0-only
-->

# RFC 0015: Multi-file Jayvee

| | |
| ----------- | --------------- | --------------------------------------------------------------- |
| Feature Tag | `multi-file` |
| Status | `ACCEPTED` | <!-- Possible values: DRAFT, DISCUSSION, ACCEPTED, REJECTED --> |
| Responsible | `georg-schwarz` | <!-- TODO: assign yourself as main driver of this RFC --> |

<!--
Status Overview:
- DRAFT: The RFC is not ready for a review and currently under change. Feel free to already ask for feedback on the structure and contents at this stage.
- DISCUSSION: The RFC is open for discussion. Usually, we open a PR to trigger discussions.
- ACCEPTED: The RFC was accepted. Create issues to prepare implementation of the RFC.
- REJECTED: The RFC was rejected. If another revision emerges, switch to status DRAFT.
-->

## Summary

This RFC introduces the possibility of distributing a Jayvee program over multiple files.
This feature will foster reuse of valuetypes, blocks, and other elements.
Inherent to this feature is a concept of how scoping and naming is handled for nested structures.
This RFC introduces two concepts:

- Element usage from other files, and
- Packages

## Motivation

Right now, Jayvee users can only pack their whole Jayvee model into one file.
The challenge is two-fold:

1. Larger projects will become unmaintainable quite quickly, as the elements cannot be organized into multiple files.
2. Without distribution to multiple files, there is no possibility to later reuse models of other projects.

## Explanation

### Element visibility

We distinguish different kinds of visibilities of elements:

- `file-private`: usable only within the same file
- `file-published`: usable also in other files of same project
- `package-private`: usable only within the package
- `package-published`: usable also in other locations (since `package` is always `file-published`)

By introducing the concept of `packages`, most elements can be defined on three scope levels in a Jayvee file:

1. file-scope (not contained in a further structure, like a pipeline or a package)
2. pipeline-scope (contained in a pipeline)
3. (new) package-scope (contained in a package)

The name of an element is given by its definition.
The **qualified name** is constructed by prepending container structures in this pattern: `<container name>.<element name>`, e.g., `MyDomainPackage.MyDomainSpecificValuetype`.

**Access paths:**

- _file-scope_ elements can access
- &#9989; _file-scope_ elements by their name
- &#9989; _package-scope_ elements by their qualified name (`packageName.elementName`)
- &#10060; no _pipeline-scope_ elements
- _package-scope_ elements can access
- &#9989; _file-scope_ elements by their name
- &#9989; elements of the same _package-scope_ by their name
- &#9989; elements of another _package-scope_ by their qualified name
- &#10060; no _pipeline-scope_ elements
- _pipeline-scope_ elements can access
- &#9989; _file-scope_ elements by their name
- &#9989; elements within the same _pipeline-scope_ by their name
- &#10060; no elements of another _pipeline-scope_
- &#9989; _package-scope_ elements by their qualified name

**Used elements** of different files are handled **as if they were defined at file scope level**.

### Publishing elements for usage elsewhere (within the project)

For publishing single elements, the RFC introduces the keyword `publish` to indicate the visibility `file-published`.
All elements within a file are not published per default, visibility `file-private`.
Explicitly declaring an element as published allows for usage elsewhere.

**Example publish**

```
// define and publish in one syntax
publish valuetype MyValueType1 {
// ... details
}
// define first
valuetype MyValueType2 {
// ... details
}
// publish later
publish MyValueType2;
// publish later under a different name
publish MyValueType2 as MyValueType3;
```

### Packages: bundling elements to a package for decoupled usage

For bundling and publishing elements, the RFC introduces a new concept called `packages`.
A `package` can include `Valuetype`s, `Block`s, `BlockType`s, `Constraint`s, `Transform`s, and further `Package`s.
A package must be of visibility `file-published` and, thus, requires the keyword `publish`.
georg-schwarz marked this conversation as resolved.
Show resolved Hide resolved
Elements within a package can be of visibility `package-published` by using the `publish` keyword, or are `package-private` per default.
`package`s within `package`s must be `publish`ed as a consequence.

**Example package**

```
publish package MyDomainPackage {
// definition of a new valuetype as part of the package
publish valuetype MyDomainSpecificValuetype1 {
// ... details of valuetype
}
// reference to an existing valuetype to make it part of the package
publish MyDomainSpecificValuetype2;
// ... possibly more elements
}
```

The advantage of bundling elements into a `package` is the decoupling from the internal file system structure and logically grouping related elements into one namespace.
Rather than accessing files directly (and needing knowledge what is element is located in which files) users can simply use a whole package with all its elements (and don't need to know in which file the element is originally defined).

### Using elements

Only `file-published` (with keyword `publish`) elements can be `use`d in other files.

#### Usage paths

When using elements of a file or a package, we have to define where the elements are located.
Jayvee provides the following possibilities:

- a relative file path, e.g., `use * from './path/to/file.jv';`

The `use` of elements via a file path decouples from the file system structure by using the element name or a defined alias instead of the file path within the file.

#### Using published elements of a file (within the same project)

```
use * from './path/to/location.jv'; // use all published elements from the file, access via qualified name as if it would be defined at the _file-scope_
use * as MyWrappingNamespace from './path/to/location.jv'; // use all published elements from the file, access via qualified name as if it was defined in an artificial _package-scope_ (adding a prefix to the qualified name)
use { MyDomainSpecificValuetype1 } from './path/to/location.jv'; // only use the published elements from the file, access via qualified name as if it would be defined at the _file-scope_
use { MyDomainSpecificValuetype1 as Vt1} from './path/to/location.jv'; // only use the published elements from the file, access via qualified name using the alias
```

References to these used elements is by their qualified name (unless altered by an alias).

#### Using a package

The `use` syntax is similar to importing an element of a file.
Packages can only be used as a whole.

```
use { MyDomainPackage } from './path/to/location.jv'; // only use the named package, access via qualified name
use {
MyDomainPackage1,
MyDomainPackage2
} from './path/to/location.jv'; // only use the named packages, access via qualified name
use { MyDomainPackage as MyPackageAlias} from './path/to/location.jv'; // only use the named package, access via qualified name using the alias
```

References to these used elements is by their qualified name (unless altered by an alias).

## Decision rationale

- keywords `publish` and `use` over `export` and `import` since they are less technical and better understandable for subject-matter experts
- concept of "namespaces" is separate from publishing them for reuse in other projects (this RFC only introduces the concept of "namespaces" by the keyword `package`)

## Drawbacks

- Two different sharing mechanisms (`publish` keyword, `package` concept`)
- Elements of a pipeline cannot be reused, leading to potentially more slim pipelines and a parallel package
- Langium might not support this scoping mechanism out-of-the-box (more complex implementation)

## Alternatives

- "use" syntax without braces, etc., `use MyDomainPackage1, MyDomainPackage2 from './path/to/file.jv';`
Copy link
Contributor

Choose a reason for hiding this comment

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

We kind of defaulted to this (I assume from TypeScript experience) but I actually agree. Why have bracers? I would remove them.

Copy link
Contributor

Choose a reason for hiding this comment

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

I really like the braces.

Without it seems like some default exports (as a TS/JS-influenced dev) or different statements (int a = 0, b = 1). Braces clarify this imo.

Copy link
Member Author

Choose a reason for hiding this comment

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

From a visual perspective, I also like the braces. Without braces, I'm unsure how very long use statements would be split into separate lines.

- switch around `use` and `from`: `from 'location' use { Element };`
- different keyword for publishing files and packages (e.g., `export`)
- different keyword for using files and packages (e.g., `import`)
- different keyword for renaming published / used elements (e.g., `called`)
- Rather call it `module` or `component` instead of `package`

## Possible Future Changes/Enhancements

- build out to use packages of other projects via a package-manager mechanism, e.g., by using an URL as location of a "use" statement
- alternative: introduce new concept `library`
- allow "using" single elements of a package instead of "using" the whole package
- allow additional usage paths, like
- absolute file paths, and
- org/repo combination at a central package registry, e.g., `use * from 'jv:my-org/my-repo';`
Loading