Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upModule import semantics #8013
Comments
dom96
added
the
RFC
label
Jun 11, 2018
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
zah
Jun 11, 2018
Member
These type of requests usually come from people who have used only dynamic languages and who are not used to having a working "Go to definition" operation in the IDE (or symbol info on mouse over).
We should educate such people instead of appealing to every request to make Nim more familiar to their way of doing things. If anything, the successful statically-typed languages feature even more implicitness with their automatically inserted this pointers in calls to base methods that may be defined in another file.
|
These type of requests usually come from people who have used only dynamic languages and who are not used to having a working "Go to definition" operation in the IDE (or symbol info on mouse over). We should educate such people instead of appealing to every request to make Nim more familiar to their way of doing things. If anything, the successful statically-typed languages feature even more implicitness with their automatically inserted |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
siddhantgoel
Jun 15, 2018
I would also love to see this handled in some way or the other. Having some sort of blanket that tells me that X comes from Y makes it quick & easy to visually parse and understand a piece of code. If a file is importing like 5 modules, this becomes especially important. The forum post describes exactly what the problem is.
These type of requests usually come from people who have used only dynamic languages and are not used to having a working "Go to definition" operation in the IDE (or symbol info on mouse over).
I'm not sure if it's only about dynamic languages or not having IDE support all the time. A lot of compiled statically typed languages support this (Go, for example). And you do end up reading a lot of code outside of your editor (say, on Github when you're trying to read some library your code is using).
I don't know - "explicit is better than implicit" is something I've come to really really appreciate. Doesn't matter if successful statically-typed languages support them or not. It could be that they're successful despite being implicit.
Anyway, I'd love to see this be a part of Nim in some form or the other. Thanks for the work you're putting in!
siddhantgoel
commented
Jun 15, 2018
|
I would also love to see this handled in some way or the other. Having some sort of blanket that tells me that X comes from Y makes it quick & easy to visually parse and understand a piece of code. If a file is importing like 5 modules, this becomes especially important. The forum post describes exactly what the problem is.
I'm not sure if it's only about dynamic languages or not having IDE support all the time. A lot of compiled statically typed languages support this (Go, for example). And you do end up reading a lot of code outside of your editor (say, on Github when you're trying to read some library your code is using). I don't know - "explicit is better than implicit" is something I've come to really really appreciate. Doesn't matter if successful statically-typed languages support them or not. It could be that they're successful despite being implicit. Anyway, I'd love to see this be a part of Nim in some form or the other. Thanks for the work you're putting in! |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
dom96
Aug 15, 2018
Member
I'm going to mark this as accepted since @Araq has pretty much accepted it in the forum.
|
I'm going to mark this as accepted since @Araq has pretty much accepted it in the forum. |
dom96
added
the
RFC: Accepted
label
Aug 15, 2018
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
dom96
Aug 15, 2018
Member
Here is my alternative proposal:
- If we have a module M with a type T and a proc p that takes T as a first parameter, attach 'p' to 'T' much like in conventional OOP languages.
- When you do
from M import Tall its operations are available too but only via the dot call syntax,obj.foo. Operators are special and also available.This will also have further benefits for how to do symbol bindings in generics later on, if a type implements an
==andhashthefrom x import Tsyntax should not lead to the hiding of these operations. Plenty of operations are affected by this, they should be more likeoverridethan likeoverload.
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
timotheecour
Aug 15, 2018
Contributor
This alternative proposal doesn't work well with generics (a common case, eg algorithms.reverse), eg:
foo.nim:
type Foo=int
proc bar1(a:Foo)=discard
proc bar2[T](a:T)=discardmain.nim
from foo import Foo
var myfoo: Foo
myfoo.bar1 #ok
myfoo.bar2 #not ok, would have to explicitly import `bar2` or not use UFCS and use `foo.bar2(myfoo)`I propose the following which allows to keep module qualified names in UFCS chains:
let a=getSomePath[0].cleanup.algorithms.reverse.furtherProcessing # doesn’t work, obviously
let a=algorithms.reverse(getSomePath[0].cleanup).furtherProcessing # breaks UFCS; gets worse if more symbols need module qualification, eg:
# mod.bar(mod.bar2(mod.bar3(arg)))
let a=getSomePath[0].cleanup.algorithms::reverse.furtherProcessing # my proposal 1 (or any simple symbol if :: is not good for some reasons, although there is precedent for it in C++ and rust)
let a=getSomePath[0].cleanup.(algorithms.reverse).furtherProcessing # alternative proposal 2|
This alternative proposal doesn't work well with generics (a common case, eg type Foo=int
proc bar1(a:Foo)=discard
proc bar2[T](a:T)=discardmain.nim from foo import Foo
var myfoo: Foo
myfoo.bar1 #ok
myfoo.bar2 #not ok, would have to explicitly import `bar2` or not use UFCS and use `foo.bar2(myfoo)`I propose the following which allows to keep module qualified names in UFCS chains: let a=getSomePath[0].cleanup.algorithms.reverse.furtherProcessing # doesn’t work, obviously
let a=algorithms.reverse(getSomePath[0].cleanup).furtherProcessing # breaks UFCS; gets worse if more symbols need module qualification, eg:
# mod.bar(mod.bar2(mod.bar3(arg)))
let a=getSomePath[0].cleanup.algorithms::reverse.furtherProcessing # my proposal 1 (or any simple symbol if :: is not good for some reasons, although there is precedent for it in C++ and rust)
let a=getSomePath[0].cleanup.(algorithms.reverse).furtherProcessing # alternative proposal 2 |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
drslump
Aug 15, 2018
Contributor
When you do from M import T all its operations are available too but only via the dot call syntax, obj.foo
Could anyone explain why have the distinction of only allowing obj.foo? Otherwise the feature looks great to me, it makes code reviewing much more tractable since it's usually easy enough to figure out a type from its surroundings.
This alternative proposal doesn't work well with generics
At least for your example I think it does, I can specify that I want to import a type Foo and also a generic function bar2.
Could anyone explain why have the distinction of only allowing
At least for your example I think it does, I can specify that I want to import a type |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
timotheecour
Aug 15, 2018
Contributor
At least for your example I think it does, I can specify that I want to import a type Foo and also a generic function bar2.
for things like std/algorithms or any module that uses generics, you'll end up importing most procs, which doesn't address the concern this issue was trying to solve (see https://forum.nim-lang.org/t/3783#23584)
Again, here is how it would look like using my proposed :::
let a=getSomePath[0].cleanup.algorithms::reverse.algorithms::fill(0)
# what that expression means is:
let a=algorithms.fill(algorithms.reverse(getSomePath[0].cleanup), 0)# (hard to read and visually parse)Note: @Araq suggested using |> in IRC but I don't know what he means; how would above expression look like with |> ?
From IRC (bridge bot) @FromIRC 14:31
for things like std/algorithms or any module that uses generics, you'll end up importing most procs, which doesn't address the concern this issue was trying to solve (see https://forum.nim-lang.org/t/3783#23584) Again, here is how it would look like using my proposed let a=getSomePath[0].cleanup.algorithms::reverse.algorithms::fill(0)
# what that expression means is:
let a=algorithms.fill(algorithms.reverse(getSomePath[0].cleanup), 0)# (hard to read and visually parse)Note: @Araq suggested using |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
getSomePath[0] |> cleanup |> algorithms.reverse |> algorithms.fill |> 0 |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
timotheecour
Aug 15, 2018
Contributor
thanks for clarifying. That objectively looks more foreign (to me at least) than proposed ::
let's add a ",":
let a=getSomePath[0].cleanup.algorithms::reverse.algorithms::fill(0, "bar").finalize
# not clear how to parse that (to me):
getSomePath[0] |> cleanup |> algorithms.reverse |> algorithms.fill |> 0, "bar" |> finalize|
thanks for clarifying. That objectively looks more foreign (to me at least) than proposed let a=getSomePath[0].cleanup.algorithms::reverse.algorithms::fill(0, "bar").finalize
# not clear how to parse that (to me):
getSomePath[0] |> cleanup |> algorithms.reverse |> algorithms.fill |> 0, "bar" |> finalize |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Araq
Aug 15, 2018
Member
That proposal of mine deals with a different, but related problem and still nobody ever made a convincing argument! So how does Go deal with this problem? Last time I checked it uses x.foo everywhere instead of module.foo(x) too...
EDIT: Er .... well ok I did propose a more useful from M import T feature, but still... what's the point, without IDE support I have to guess where to find a name. And that's true for Python, Go, C#, C++, C, Lua, ...
|
That proposal of mine deals with a different, but related problem and still nobody ever made a convincing argument! So how does Go deal with this problem? Last time I checked it uses EDIT: Er .... well ok I did propose a more useful |
Araq
removed
the
RFC: Accepted
label
Aug 15, 2018
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
drslump
Aug 15, 2018
Contributor
Ooops! and here I was thinking what a stroke of genius that was to make explicit imports ergonomic
Thanks for clarifying!
|
Ooops! and here I was thinking what a stroke of genius that was to make explicit imports ergonomic Thanks for clarifying! |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
|
I like the way nim does imports. Please don't change. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
drslump
Aug 16, 2018
Contributor
I did propose a more useful from M import T feature, but still... what's the point, without IDE support I have to guess where to find a name
The point is simplify reading code bases that aren't very familiar to the reader, and that includes:
- code reviewing on a large team
- skimming over a library's source code on github
- minor: make snippets more explicit for casual sharing (email, docs, forum, stackoverflow, ...)
To me the code reviewing one is a killer feature, it probably depends on how a team works and I'm sure it varies a lot across the industry, but for anyone using a "microservices" approach on a large team you end up having to review a mix of languages/libraries/domains and every bit that helps with that counts. Improving from m import T makes it a viable alternative that can be opt-in by those that value that explicitness while not affecting those that don't.
The point is simplify reading code bases that aren't very familiar to the reader, and that includes:
To me the code reviewing one is a killer feature, it probably depends on how a team works and I'm sure it varies a lot across the industry, but for anyone using a "microservices" approach on a large team you end up having to review a mix of languages/libraries/domains and every bit that helps with that counts. Improving |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Araq
Aug 16, 2018
Member
Yes, you don't have to repeat these claims. You have to back them up with science. So how do I figure out where imshow is declared. Context: https://github.com/matplotlib/matplotlib/blob/master/examples/color/colormap_reference.py#L57
Must be simple, after all, Python uses these superior import rules you're talking about.
|
Yes, you don't have to repeat these claims. You have to back them up with science. So how do I figure out where Must be simple, after all, Python uses these superior import rules you're talking about. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
drslump
Aug 16, 2018
Contributor
Sorry, I'll try to refrain myself from repeating stuff. No science backed stuff unfortunately, just my personal experience, which amounts to nothing, and that's why I didn't claim explicit imports were superior, just that they work better for some use cases.
imshowis a method ofaxaxcomes from theaxescollectionaxesis obtained from theplt.subplotsfunctionpltis an alias for modulematplotlib.pyplot
I don't need to compile the code in my head when looking at the source, just be able to quickly navigate it visually, often times I'll find on the way some interface I know so no need to traverse the whole path all the time.
|
Sorry, I'll try to refrain myself from repeating stuff. No science backed stuff unfortunately, just my personal experience, which amounts to nothing, and that's why I didn't claim explicit imports were superior, just that they work better for some use cases.
I don't need to compile the code in my head when looking at the source, just be able to quickly navigate it visually, often times I'll find on the way some interface I know so no need to traverse the whole path all the time. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Araq
Aug 16, 2018
Member
Ok, that remains completely unconvincing, sorry. In practice I git clone the repo and search for it with the best tool at hand and are far more quickly to get reliable results than this educated guess of tracking stuff backwards where you pray no subtyping in the axes collection occurs and who knows what other implicit assumptions this tracking makes.
|
Ok, that remains completely unconvincing, sorry. In practice I |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
zah
Aug 16, 2018
Member
Better long term-solution that will appear - A browser extension targeting Github overlays additional semantic information (such as hover tooltips and "Go to definition" on right click) right into the rendered code on Github.
|
Better long term-solution that will appear - A browser extension targeting Github overlays additional semantic information (such as hover tooltips and "Go to definition" on right click) right into the rendered code on Github. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Araq
Aug 16, 2018
Member
Here is an argument that is much more convicing to me:
from tables import CountTable
var x: CountTable[string]
x.add 4
# Error: type mismatch
# list of 'add' candidates here but exluding Table.add!But this error message will be improved in a different way, we won't list the overloads that don't match the first argument if there any where the first argument matches.
|
Here is an argument that is much more convicing to me: from tables import CountTable
var x: CountTable[string]
x.add 4
# Error: type mismatch
# list of 'add' candidates here but exluding Table.add!But this error message will be improved in a different way, we won't list the overloads that don't match the first argument if there any where the first argument matches. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Araq
Aug 16, 2018
Member
And as a peace treaty we might as well add from M import T with the outlined scope injections. For me it's a pure "feeling good" feature, but we want our users to feel good. :-)
|
And as a peace treaty we might as well add |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
drslump
Aug 16, 2018
Contributor
that's good to hear! If someone offers to mentor me I would be super glad to work on the feature.
|
that's good to hear! If someone offers to mentor me I would be super glad to work on the feature. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Araq
Aug 16, 2018
Member
Edit compiler/importer.nim to import "stuff that obviously belongs to T" for "from M import T" if it's enabled via {.experimental: "typeImports".}.
|
Edit |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
dom96
Aug 16, 2018
Member
And as a peace treaty we might as well add from M import T with the outlined scope injections. For me it's a pure "feeling good" feature, but we want our users to feel good. :-)
That is all I ask for. This isn't about changing what import module means, it's about making the from module import Type better.
I do consider it an experiment, and I would like to hear whether it makes Python users more comfortable.
That is all I ask for. This isn't about changing what I do consider it an experiment, and I would like to hear whether it makes Python users more comfortable. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Araq
Aug 16, 2018
Member
I do consider it an experiment, and I would like to hear whether it makes Python users more comfortable.
I agree, which is why this needs to be enabled via {.experimental: "typeImports".}.
I agree, which is why this needs to be enabled via |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
dom96
Aug 16, 2018
Member
Yes, you don't have to repeat these claims. You have to back them up with science. So how do I figure out where imshow is declared. Context: https://github.com/matplotlib/matplotlib/blob/master/examples/color/colormap_reference.py#L57
Must be simple, after all, Python uses these superior import rules you're talking about.
Another argument:
Sure, there are cases where it's not easy to find where symbols are defined in Python. But you know the saying "Don't make perfect the enemy of the good?" of course you do. Python might not make 100% of symbols easy to find, but it does make it easy to find the 95% of symbols in your code. To most people that's a huge benefit.
Another argument: Sure, there are cases where it's not easy to find where symbols are defined in Python. But you know the saying "Don't make perfect the enemy of the good?" of course you do. Python might not make 100% of symbols easy to find, but it does make it easy to find the 95% of symbols in your code. To most people that's a huge benefit. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
Araq
Aug 16, 2018
Member
It took me very little time to find this example, for me Python code is full of this problem, so you would need to back up that 95% number.
|
It took me very little time to find this example, for me Python code is full of this problem, so you would need to back up that 95% number. |
dom96 commentedJun 11, 2018
One of the number 1 complaints about Nim is the semantics of
import module: the fact that all identifiers can be referred to without an explicit namespace.I keep seeing this again and again on HN/Reddit. I'd love to give developers who view this as a problem a chance to suggest alternatives. But my main reason for creating this issue is to keep track of this alternative proposal on the forum: https://forum.nim-lang.org/t/3783.