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

Allow explicit imports #2354

Closed
kritzcreek opened this issue Feb 15, 2021 · 6 comments · Fixed by #3076
Closed

Allow explicit imports #2354

kritzcreek opened this issue Feb 15, 2021 · 6 comments · Fixed by #3076
Assignees
Labels
feature New feature or request language design Requires design work P2 medium priority, resolve within a couple of milestones Story

Comments

@kritzcreek
Copy link
Contributor

kritzcreek commented Feb 15, 2021

Story

As a developer, I want to be able to explicitly import unqualified types and functions from other modules.

Motivation

Currently we can only import modules as a whole with a qualified identifier.
This leads to a lot of Result.Result which looks silly, and makes people create module local private aliases.
This is bad because:

  1. They're adding boilerplate to work around compiler limitations
  2. They don't get hyperlinked documentation because their type signatures point to module local private type definitions.

Demo
I want something like this to compile

    import Result "Result";
    // Showcases both type as well as value level imports
    import { type Result, mkErr } "Result";
    
    module {
      public fun fromOption<Ok, Err>(err: Err, opt: ?Ok) : Result<Ok, Err> {
        switch opt {
          case null { mkErr(err) };
          case (?ok) { Result.mkOk(ok) };
        };
      };
    }

Design

This doesn't just work if we allow object patterns, because we can't project type components that way.

It might also be nice to have a more compact format for the "import both as qualified and explicit" pattern, as shown above.

@kritzcreek kritzcreek added language design Requires design work Story labels Feb 15, 2021
@rossberg rossberg mentioned this issue Feb 15, 2021
28 tasks
@nomeata
Copy link
Collaborator

nomeata commented Feb 15, 2021

This doesn't just work if we allow object patterns, because we can't project type components that way.

Would that be hard to add, @crusso? Would this make sense as a orthogonal feature?

It might also be nice to have a more compact format for the "import both as qualified and explicit" pattern, as shown above.

Again, if we add as patterns (the dual of Alt, @) to the language, we could use this here, right?

@crusso
Copy link
Contributor

crusso commented Feb 26, 2021

Yes, I think this might be doable, hopefully just by extending object patterns and allowing imports with non-trivial patterns. Not sure how type field patterns would look for synthesized (not checked) patterns though - I guess you'd just have to provide the type definition.

The other question is whether you should be allowed to refer to the type identifier within the enclosing pattern, or just in continuation of the let. I also worry that our super-liberal recursion might pose problems here.

@nomeata
Copy link
Collaborator

nomeata commented Feb 26, 2021

Can’t you always desugar (conceptually) object patterns into accessors? If so, then hopefully there are no (conceptual) problems with recursive typing. But only trying it will tell…

@rossberg
Copy link
Contributor

@crusso, I think it's inevitable that type fields are not allowed in synthesis patterns. But the only place with synthesis patterns are functions parameters, where they do not seem particularly useful anyway.

@nomeata, desugaring only works for patterns in analysis position, but those are unproblematic anyway. It's the synthesis case that we cannot handle. Consider:

func f({a; type B}) { ... }

@nomeata
Copy link
Collaborator

nomeata commented Feb 26, 2021

Is that different from the following?

func (o) { do { let a = o.a; type B = o.B; … } }

@rossberg rossberg added the P2 medium priority, resolve within a couple of milestones label May 18, 2021
@ggreif
Copy link
Contributor

ggreif commented Jan 27, 2022

EDIT: please ignore most of what follows. #3076 implements specific imports and the pattern syntax { external = local } allows renaming out of the box.


Wouldn't this be an instance of an and pattern with the small twist that the RHS is a label pattern (appearing in the record to be destructured) and that only applies to record values? Also the RHS is meant to be hidden from the enclosing/importing scope, right? Thus there are only bindings in the LHS, and stuff gets much easier to check.

Just spotted #2354 (comment) above, we seem to be in agreement! @nomeata

import { type Result; mkErr = fooErr } "Result";

would import fooErr renamed as mkErr. Thus this could be regarded as the pattern dual of unpunned field definitions when building records. Also, in turn instead of the named pattern mkErr, we could further deconstruct.

@ggreif ggreif added the feature New feature or request label Jan 27, 2022
ggreif added a commit that referenced this issue Jan 27, 2022
@ggreif ggreif self-assigned this Jan 27, 2022
@mergify mergify bot closed this as completed in #3076 Jan 28, 2022
mergify bot pushed a commit that referenced this issue Jan 28, 2022
…ield import (#3076)

Resolves #2354, the bulk of it.

We can now import subsets of modules:
``` Motoko
import { cons; nil = empty } = "lib/ListM";

let s = cons(1, empty());
```
Yay!

These will be done separately:
- importing of `type` fields explicitly,
- dealing with explicit imports in the `languageServer` (#3078).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request language design Requires design work P2 medium priority, resolve within a couple of milestones Story
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants