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

Import syntax #103

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open

Conversation

jackdotink
Copy link
Contributor

This RFC proposes import syntax like the following:

import myname, type mytype, myname2, type mytype2 from "mymodule"

Rendered.

@Almost89
Copy link

Almost89 commented Feb 21, 2025

My previous message sounded a lot harsher than intended and I would like to apologize, but my two main questions were:

  • Why do the items imported come before the path? From my experience in JavaScript, the autocomplete was worse because of it. However, it was pointed out that this a non-issue and is already done in lots of other languages with significant benefit.
  • Was a "default" import syntax considered or is that a feature for a future RFC?

@surfbryce
Copy link

@Almost89 There are plenty of languages that have auto-complete for the suggested syntax implementation which always ends up being better than the explicit "from this import these".

When using the latter approach you only start getting auto-complete suggestions once the path has been defined for it to draw these suggestions from. In the former approach we can get auto-complete suggestions based on the indices being typed and then can choose the desired path based off that.

The former approach will always be better because of this. It goes from having to remember the path your desired value is in to just simply having to remember the import index for that value (which is typically just the name of the Value itself) and then having intellisense/auto-complete present to you the import options for that value.

Also for the module name being implicitly imported, it most likely wouldn't be and is simply a misleading formatting issue. Realistically it would be equivalent to just the below indexing.

@jackdotink
Copy link
Contributor Author

@Almost89
Imported items come before the path because that is what is more important. Users will generally not write import statements, instead having them autocompleted in by their lsp. Instead, when reading code, especially in an environment without an lsp like github, when someone wishes to find where something comes from they want to scan "what is imported" before "where it's from". Overall this is just a style thing - I don't think it really matters either way.

I did not consider a default import, but I do think it is viable. I think the syntax import default name from "module" would work best, with the usage of this syntax disallowing anything else but type imports. Let me know what you think and then I'll put something in the RFC.

@Wunder-Wulfe

This comment was marked as resolved.

@jackdotink
Copy link
Contributor Author

jackdotink commented Feb 23, 2025

@Wunder-Wulfe
I specifically designed the syntax to not introduce any ambiguities. In EBNF, import STRING would not be a valid import, and would be parsed as a function call statement; import NAME would be the only valid start to an import.

I find using hot comments to be horrific, and a function would not be meaningfully different from require.

None of the example code you provided is at all similar or representative of any example code in the RFC, which leads me to believe you did not read it. Please do so before making more comments.

@dphfox
Copy link

dphfox commented Feb 23, 2025

I previously had a similar idea a while ago in the old repo; at the time I thought it would be a reasonable alternative to more general destructuring syntax like you do here. As I understand it, this syntax:

import useState, useMemo from "react"

Would basically mean you could never have anything that could be interpreted as a function call in that list of identifiers, which is unpalatable (but nonetheless, theoretically workable...)

However, over time I've thought about it a lot more and it really seems like whatever syntax we would choose for an import syntax should align with destructuring syntax anyway, in case the call is made to allow destructuring for local variable declarations too, thus not really sidestepping the problem at all.

This would rule out the use of a contextual keyword at the start of the statement.

local { .useState, .useMemo } from "react"

At that point, you may as well just use destructuring with the normal import system, unless you're particularly motivated to have a nice syntax for this.

local { .useState, .useMemo } = require("react")

So I don't think this is the right path to go down.

@jackdotink
Copy link
Contributor Author

I somewhat agree, though I am unsure if destructuring syntax will be added. I also feel that this syntax more closely aligns with Luau's export syntax.

Consider this an alternative for when destructuring fails to be accepted once again.

@aatxe
Copy link
Contributor

aatxe commented Feb 24, 2025

Worth noting the similarity with #97 too, fwiw.

@gaymeowing
Copy link
Contributor

gaymeowing commented Feb 27, 2025

Would be nice if this rfc allowed for

import all from "./react"

And this for all types

import types from "./react"

Also perhaps worth considering having file paths as first class?

@loukamb
Copy link

loukamb commented Mar 4, 2025

Could this be transformed into the killer destructuring syntax we're all looking for, actually? The from keyword specified in the RFC would introduce a new keyword for a single purpose, and it would be a shame if the usefulness of its introduction wouldn't be extended to, for example,

local t = { a = 1, b = 2 }
local function f()
    local a, b from t
    print(a, b)
end

Then you can have the module-like import syntax like this:

-- Import specific fields.
local useState, useEffect from require("react")

-- Import everything.
local react = require("react")

-- Also import from a ModuleScript!
local coolMethod, coolFunction from require(game:GetService("ReplicatedStorage").CoolModule)

This would introduce two features for a new keyword instead of a single one. It can also be extended to globals if anyone wants to by also accounting for a, b from t without the need to prefix the statement with local.

-- Import variables into the global environment.
table, string from require("./my-cool-env-extensions.lua")

IMO this version's ability to declare imported variables as either local or global makes it a better fit for the language than the current RFC since the syntax introduced by the RFC doesn't explicitly specify the locality of the imported variables (you have to assume that they will only be available within the current file).

@jackdotink
Copy link
Contributor Author

@loukamb
Anything that affects the global environment is a non-starter imo. This RFC doesn't really add a keyword in the traditional sense that it reserves it - it is fully contextual, only a bit of nice syntax. Those other examples could be added, but that should be done in a separate RFC.

@loukamb
Copy link

loukamb commented Mar 4, 2025

Syntactical minimalism aside, I don't see an issue with adding a contextual keyword, but if one is to be added, it would be nice to give it additional functionality. A separate RFC can written but it would make this RFC redundant (it provides the same user-facing advantages as a built-in import statement), code processors/bundlers notwithstanding. I do understand that a very predictable import statement form eases parsing module imports, and my suggestion would make that parsing a tiny bit less predictable as it involves an expression.

The global import assignment is for parity with standard assignments. local can be learned and approached as a scope-modifying keyword that can be added to or removed from a variable assignment, even though it is structured as two different statements in the parser. My suggestion assigns variables, and therefore local should be addible and removable. The mutability of the global environment in Lua(u) is an awkward feature that very occasionally deserves to be remembered, the poor thing!

@jackdotink
Copy link
Contributor Author

jackdotink commented Mar 5, 2025

The mutable global environment should not be remembered except by embedders.

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

Successfully merging this pull request may close these issues.

8 participants