-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
2.0: just one import keyword #39235
Comments
I like all of that. |
Duplicate of #8000 |
I don't think I feel that way julia would change to more python-like style when you shouldn't |
Did you mean "an implicitly imported generic function"? |
I think it's all good, except I would drop |
How is the current " |
I apologize in advance for bikeshedding, but maybe it would be more ergonomic to base the new import system on the defaults adopted by using Foo.Bar, Foo.Bar2 as Baz, Foo.Bar3 as _ The above creates soft bindings to the exported symbols within using Foo.Bar: baz, qux Creates hard (extendable) bindings to using Foo.Bar: baz, qux, ... Same as before, but also creates soft bindings to everything else in Edit: importing just the module name without any contained bindings could be done with using Foo.Bar: _
|
I hate |
I think @s-valent's point is not that we should adopt that syntax, but rather a comment that this proposal would put us down the same road as Python, which discourages |
I absolutely did not suggest to add |
Looking at the table, the new form doesn't appear simpler or clearer to me. I'd argue it makes the syntax more complex. Some of the changes can also be done without removing Additionally, and as mentioned above, how would the current I would vote to keep the The proposed hard vs soft binding changes would get a 👍 from me. |
It sounds like with the proposal there's no way to have the semantics of |
Here are the things one may want to do when importing a package, along with how to do them currently:
The main motivations for my proposed changes are:
A non-objective is to make it possible to import things from multiple packages in a single statement. I'm fine with that when there's an obvious and convenient syntax for it, but it's just not one of my motivations. One of the annoyances of the current The explicitly named import versus implicit import rule addresses the subtle distinction between The reason to use It would also be viable to keep |
just FYI, a keyword |
I'll repeat what I said before: over my dead body are we introducing |
Well not exactly |
For what it's worth, I'm pretty far from sold on the file import discussed in #4600, but I think that's fairly orthogonal to this issue. If we have |
Maybe wer're just using it wrong 😄. I could see import Foo from "foo.jl" as F: bar, baz, ... |
OK. Sorry for the noise. |
You don't need the |
Actually, I was thinking of the case where "foo.jl" contains an actual, declared module Foo. If |
We should really have this discussion on #4600, not here. |
|
This probably isn't a popular opinion, but I'd be all for just removing the The equivalent Python syntax |
I don't really get this. If it's "usually a bad practice" how does the syntax vibe being similar to
This isn't going to happen since it's way too annoying to have to explicitly import all names for interactive use. There's a case to be made that it shouldn't be used in other situations, but it's really convenient there too and because of the way the mechanism is designed, it doesn't actually cause any problems unless two different packages export the same name with a different meaning, in which case you get a clear and specific error message. Perhaps things are worse in Python, but this isn't that big a deal in Julia. My objection to |
One thing I'd really like is a way to using Foo except bar I know this is semi-orthogonal, but I think it'd be important to think about how a unified syntax like this might be generalized further. Would the above (currently non-syntax) become something like import Foo: ... except bar ? I guess that's not as bad as it seemed in my head, but it does feel a little less clear than the |
Sorry if this is noise. But from the perspective of someone which is not a developer of "core" packages, the distinction of I understand that for packages that are extending many functions of other packages having one syntax is nice, and I do not see any reason to not allow all that flexibility to (as a side note: why not |
@lmiq because |
@Moelf but is |
This suggests importing the |
A way of evaluating how confusing or clarifying this change might be for users, is to compare the current table in the summary of module usage in the docs with how it would look after the change. If I got the intention right, the proposed change would mean: (a) dropping the second line ( From my point of view, (a) does indeed simplify things; (b) makes it more consistent - |
I don't see the point of |
This would fix #39235 |
In fact, this is #39235. |
ERROR: StackOverflowError:
Stacktrace:
[1] goto(::#39235) (repeats 79984 times)
@ Main ./REPL[5]:1 |
Of course, that is why it would fix it. Oh, and additionally, it would fix #29275. |
FYI, as someone who has high myopia, |
Would we lose the ability of making explicit soft bindings, as in using Foo: some_function ? Personally, in packages I always prefer to have an explicit list of symbols I am using from other packages and not rely on export lists, so |
My personal favorite would be to make the import statement fully generic and have the export statement support the same syntax to allow for different ways of exporting. Creative generalization processOkay, so where are we? import list, elements, to, be, imported
#well yes, syntactically kinda looks like
return multi, argument, response in the latter case it's syntactical sugar for a tuple. So what happens if we'd interpret the import statement as using a tuple? import as named tupleWe could ask, what about named tuples? This immediately leads to an intuitive understanding of named imports. import OtherModule: foo=bar, foo2=bar2 Optionally we can think whether we'd prefer/allow writing hard bindings?I remember a certain rule about individual labels after a semicolon in named tuples, i.e., #old:
using Foo: soft
import Foo: hard
#new (long):
import Foo: soft, hard as hard
#new (short by named tuple mechanics):
import Foo: soft; hard So including the splat operator this could lead to: #old
using Foo
using Foo: soft, binding
import Foo: hard, bind
#new
import Foo: ..., soft, binding; hard, bind
#maybe also allow
import Foo
#as shorthand for
import Foo: ...
#which previously was
using Foo On the way to even more generalization, I now can ask, what happens if I splat behind the semicolon (=the hard binding area)? Next: generic exportNow, that we have a generic import, let's make export generic as well. export Bar: soft, binding, ... #would export soft and binding from Bar and also all exports from Bar -> reexport
export bind # exports local "bind" as usual I could see some uses for that reexporting hard bind in export?Given that we have a hard binding for import, want it fully generic and still need a good use for the splat in the hard import, what could we do with the semicolon syntax for export?
Thinking a bit more
I.e., a soft import splat will just ignore the hard export and vice versa. The "hard import"-splat will import (and bind) everything that's in "hard export" and the "soft import"-splat will import (softly) everything that's in the "soft export". That way a developer would be able to have 2 different export sets: one for ordinary soft binding, used for ordinary calling usage. And one which will go into the splat that does a hard bind. Which makes it perfect for marking functions whose purpose is to be extended. Hard exports and soft exports don't have to be disjunctive, but they can. module Exporter
export soft, soft2, soft3; hard, hard2
end
module ImportSoft
import Exporter: ...
#loads soft, soft2 and soft3 without doing a hard bind
end
module ImportHard
import Exporter: soft; soft2, ...
# will soft bind "soft" and hard bind "soft2", "hard" and "hard2" but not load soft3
end Backlog 1: what about splatting for the export side?well, in order to be able to have both export sets disjunctive, we cannot make either be included in the other set. More precisely, automatically exporting soft-export bindings as hard exports doesn't make sense because those usually aren't meant to be extended, and the other way around doesn't make sense either in many cases. For those cases where I want all soft exports to be exported as hard exports as well, we could make the "splat" in the hard export refer to all soft exports and vice versa. The case that both exports are splatted would just make both sets the same. (=union of all explicit labels) Backlog 2: excluding individual importsIntroduce an exclamation mark for exclusion if needed. This would need special casing the operator itself but since functions cannot start with an exclamation mark, and it usually referring to negation I find the choice quite intuitive. (aside of module Bar
import Foo: ..., !excluded
#imports everything exported by Foo EXCEPT "excluded"
end ConclusionSyntaximport Module as Alias: <soft binding labels>; <hard binding labels>
export <goes into soft binding splat>; <goes into hard binding splat>
export OtherModule: <into soft binding splat>; <into hard binding splat> #-> reexport Advantages:
Personal intent/opinionI hope all these ideas spark a fruitful discussion whether we need a keyword instead of the semicolon for better readability or whether this is fine just as proposed. Given that we already have trained eyes for spotting the semicolon thanks to keyword arguments, I find it a valid option. Especially since you only need the semicolon part if you're a library developer or intend to extend a library (and don't want to use full qualification). An ordinary user who is just chaining method calls can stick to not using semicolon at all. |
Coming from Common Lisp where I have acquired a very opinionated idea of readable code, I am not very keen on |
Apply @jebej's suggestions in JuliaLang/julia#39235 (comment), rebased onto master
Apply @jebej's suggestions in JuliaLang/julia#39235 (comment), rebased onto master
Regardless of the eventual syntax for |
We really want to go in the opposite direction: code loading should be more statically resolvable, not less. |
I would very much like to have just one import keyword in Julia 2.0. I don't much care if it's
import
orusing
but since we talk about it as "importing" things, that may be more natural. With #39187 and some requirement for explicitly requesting extension of external generic functions, this would be possible.import Foo
import Foo
Foo
import Foo: Foo, bar
import Foo: bar
import Foo: bar
importsFoo
alsoimport Foo: bar
import Foo as _: bar
Foo as _
to discard that nameusing Foo
import Foo...
using Foo
import Foo: ...
using Foo; using Foo: bar
import Foo: bar, ...
using Foo as _
import Foo as _: ...
Foo as _
to discard that nameIn 2.0 I think we should eliminate the distinction between the "soft binding" that
using
creates and the hard binding thatimport
creates and just make all explicit bindings hard and all implicit bindings soft: if you asked for it by name, it's a hard binding, if you didn't, it's a soft binding. When someone wants to extend an implicitly imported generic function, they have to fully qualify it.The text was updated successfully, but these errors were encountered: