digitalmars.D - Pathological import symbol shadowing
- H. S. Teoh (23/23) Nov 13 2020 Just ran into this today:
- Timon Gehr (6/34) Nov 13 2020 Told you so. :P
- Kagamin (5/8) Nov 14 2020 You mean the code should not compile because symbols from
- Paul Backus (6/14) Nov 14 2020 An ambiguity error only occurs if a matching function is found in
- Kagamin (6/7) Nov 14 2020 Ah, ok.
- Paul Backus (13/21) Nov 14 2020 Yes, it is incorrect. In reality, it produces an error:
- Walter Bright (4/18) Nov 15 2020 Using:
- Timon Gehr (28/51) Nov 15 2020 Straw man. Seeing that we're at it: It's also a strange idea to write a
- Walter Bright (20/44) Nov 17 2020 Doing "import std;" is just asking for trouble. I argued against it for ...
- Paul Backus (7/26) Nov 17 2020 Because std.file is imported locally, the call to write calls
- Walter Bright (3/10) Nov 20 2020 Yes. This is why I asked, as I wondered if I was missing something.
- Timon Gehr (20/78) Nov 17 2020 There is no collision with proper overload resolution. The error is
- Walter Bright (15/27) Nov 20 2020 I don't remember the details, it was several years ago. And the fact tha...
- H. S. Teoh (17/27) Nov 21 2020 The problem is that this concept of scoping is very counterintuitive:
- Timon Gehr (8/19) Nov 21 2020 You can have three modules where module `A` imports module `B` and `C`
- FeepingCreature (17/41) Nov 18 2020 This is why our style guide doesn't allow unqualified imports in
- Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= (4/8) Nov 18 2020 Is it possible to imply an import by fully qualifying the path?
- Timon Gehr (11/60) Nov 18 2020 I'd hate that. It would make D less viable for writing small scripts.
- H. S. Teoh (68/84) Nov 18 2020 There are several factors at work here.
- matheus (18/28) Nov 18 2020 Yes that's true, but on the other hand you will need to duplicate
- Paul Backus (16/23) Nov 18 2020 std.curl.get is absolutely not at fault here. The whole point of
- Kagamin (4/7) Nov 18 2020 No way, they are correctness and performance feature. Look at STL
- FeepingCreature (3/10) Nov 19 2020 I think the problem with C++ is more transitive imports than
- Mathias LANG (8/15) Nov 18 2020 Wouldn't *that* allow hijacking? Unless of course you remove
- Timon Gehr (7/25) Nov 18 2020 How it should work:
- H. S. Teoh (6/13) Nov 18 2020 +1, this is the way it should have been from the beginning.
- Vladimir Panteleev (3/14) Nov 20 2020 Can we fix this particular case by adding "public import object;"
Just ran into this today: void main() { int[string] aa; int x; x = aa.get("abc", 123); // OK import std; x = aa.get("abc", 123); // Error: template std.net.curl.get cannot deduce function from argument types ... import std, object; x = aa.get("abc", 123); // OK } I know there's technically an explanation of this in terms of how the compiler implements import, but seriously, this is extremely annoying and confusing behaviour. Especially because the symbol being hijacked comes from the implicitly-imported object.d. Newbies wouldn't even *know* where to look if they encountered this error. D's import implementation was supposed to be designed to prevent symbol hijacking, but in this case it's falling flat on its face. Why can't we make it so that symbols that aren't explicitly named on the import line would add to existing overload sets instead of replacing them? T -- Recently, our IT department hired a bug-fix engineer. He used to work for Volkswagen.
Nov 13 2020
On 13.11.20 23:57, H. S. Teoh wrote:Just ran into this today: void main() { int[string] aa; int x; x = aa.get("abc", 123); // OK import std; x = aa.get("abc", 123); // Error: template std.net.curl.get cannot deduce function from argument types ... import std, object; x = aa.get("abc", 123); // OK } I know there's technically an explanation of this in terms of how the compiler implements import, but seriously, this is extremely annoying and confusing behaviour. Especially because the symbol being hijacked comes from the implicitly-imported object.d. Newbies wouldn't even *know* where to look if they encountered this error. D's import implementation was supposed to be designed to prevent symbol hijacking, but in this case it's falling flat on its face. ...Told you so. :P https://issues.dlang.org/show_bug.cgi?id=10378 https://issues.dlang.org/show_bug.cgi?id=17589Why can't we make it so that symbols that aren't explicitly named on the import line would add to existing overload sets instead of replacing them?It should just use the standard import rules with overload sets. Then the code above would just work and no hijacking would be possible.
Nov 13 2020
On Saturday, 14 November 2020 at 03:10:34 UTC, Timon Gehr wrote:It should just use the standard import rules with overload sets. Then the code above would just work and no hijacking would be possible.You mean the code should not compile because symbols from different modules are in different overload sets? But then get from curl will always conflict with get in object, and thus will be unusable without renaming or FQN.
Nov 14 2020
On Saturday, 14 November 2020 at 14:13:32 UTC, Kagamin wrote:On Saturday, 14 November 2020 at 03:10:34 UTC, Timon Gehr wrote:An ambiguity error only occurs if a matching function is found in both overload sets. [1] Since std.net.curl.get and object.get have completely different signatures, no function call will ever match both of them, so there will be no error. [1] https://dlang.org/spec/function.html#overload-setsIt should just use the standard import rules with overload sets. Then the code above would just work and no hijacking would be possible.You mean the code should not compile because symbols from different modules are in different overload sets? But then get from curl will always conflict with get in object, and thus will be unusable without renaming or FQN.
Nov 14 2020
On Saturday, 14 November 2020 at 14:43:16 UTC, Paul Backus wrote:[1] https://dlang.org/spec/function.html#overload-setsAh, ok. foo(1L); // calls A.foo(long) This line looks incorrect. If there was no foo(long), foo(1L) would call foo(int), then if foo(long) appears, the call will be silently diverted.
Nov 14 2020
On Saturday, 14 November 2020 at 15:48:47 UTC, Kagamin wrote:On Saturday, 14 November 2020 at 14:43:16 UTC, Paul Backus wrote:Yes, it is incorrect. In reality, it produces an error: Error: function B.foo at B.d(4) conflicts with function A.foo at A.d(3) However, the reason for this is that the literal `1L` is treated as both an int and a long for the purposes of overload resolution, because the compiler can prove that its value will fit into both types. If you change it to a variable: long l; foo(l); ...then A.foo(long) is selected unambiguously, and removing it will cause an error ("no overload matches") rather than calling B.foo(int).[1] https://dlang.org/spec/function.html#overload-setsAh, ok. foo(1L); // calls A.foo(long) This line looks incorrect. If there was no foo(long), foo(1L) would call foo(int), then if foo(long) appears, the call will be silently diverted.
Nov 14 2020
On 11/13/2020 2:57 PM, H. S. Teoh wrote:Just ran into this today: void main() { int[string] aa; int x; x = aa.get("abc", 123); // OK import std; x = aa.get("abc", 123); // Error: template std.net.curl.get cannot deduce function from argument types ... import std, object; x = aa.get("abc", 123); // OK }Using: import std; is a bad idea.
Nov 15 2020
On 15.11.20 10:06, Walter Bright wrote:On 11/13/2020 2:57 PM, H. S. Teoh wrote:Straw man. Seeing that we're at it: It's also a strange idea to write a program that does not perform any I/O. Also, obviously the AA is overkill, we could just assign 123 to x, which the snippet does three times in a row, but x is never read again! Writing that code is a bad idea; just use void main(){} instead, it will do what you wanted, and without any compilation errors. :o) I think it's safe to say that the snippet was written to illustrate a point and to focus on anything else to the detriment of a discussion of that point is just deflection. If the language was working properly, the code would compile and run fine. There is a hole in the design of the language here. There's no need to prioritize this particular issue, but I don't understand why you don't just acknowledge that this is not how the compiler should behave in this situation. It's not just rejects-valid either, this issue has accepts-invalid cases: --- import std.stdio; string readAndLog(string filename){ import std.file; auto text=readText(filename); write(filename," read successfully!\n"); return text; } void main(){ writeln(readAndLog("important_data.txt")); } ---Just ran into this today: void main() { int[string] aa; int x; x = aa.get("abc", 123); // OK import std; x = aa.get("abc", 123); // Error: template std.net.curl.get cannot deduce function from argument types ... import std, object; x = aa.get("abc", 123); // OK }Using: import std; is a bad idea.
Nov 15 2020
On 11/15/2020 6:24 AM, Timon Gehr wrote:Straw man.Doing "import std;" is just asking for trouble. I argued against it for years, and yet it was slipped in a few months ago without my knowledge. Having everything in Phobos in scope is just causing trouble. For just one of the problems, it prevents adding new modules to Phobos as it can break existing code. For another, it turns the world's fastest compiler into a pig. The example given was another example of why it's a bad idea, as the more names there are the more the likelihood of a collision.I think it's safe to say that the snippet was written to illustrate a point and to focus on anything else to the detriment of a discussion of that point is just deflection.Teoh would have never run into this issue if he hadn't used import std; I don't blame Teoh, a user should expect that import std; should not cause problems although the problems are inevitable. It should NEVER have been added to Phobos.If the language was working properly, the code would compile and run fine. There is a hole in the design of the language here. There's no need to prioritize this particular issue, but I don't understand why you don't just acknowledge that this is not how the compiler should behave in this situation.Frankly, I don't know how the compiler should behave. The original import scheme was simple, sound, and easy to explain, but everyone complained it wasn't "intuitive" and put in a complex scheme full of special cases. Complex special cases produce an endless stream of unanticipated special cases. Altering how the compiler does lookups now, regardless of how it "should" behave, could break existing code in mysterious ways. Especially if one imports every symbol in existence into a local scope :-(It's not just rejects-valid either, this issue has accepts-invalid cases: --- import std.stdio; string readAndLog(string filename){ import std.file; auto text=readText(filename); write(filename," read successfully!\n"); return text; } void main(){ writeln(readAndLog("important_data.txt")); } ---Please elaborate on what is invalid about it? Don't make me guess!
Nov 17 2020
On Wednesday, 18 November 2020 at 01:11:35 UTC, Walter Bright wrote:Because std.file is imported locally, the call to write calls std.file.write instead of std.stdio.write, and overwrites important_data.txt. If `import std.file` is moved to module scope, the compiler correctly diagnoses that the call is ambiguous.It's not just rejects-valid either, this issue has accepts-invalid cases: --- import std.stdio; string readAndLog(string filename){ import std.file; auto text=readText(filename); write(filename," read successfully!\n"); return text; } void main(){ writeln(readAndLog("important_data.txt")); } ---Please elaborate on what is invalid about it? Don't make me guess!
Nov 17 2020
On 11/17/2020 5:19 PM, Paul Backus wrote:On Wednesday, 18 November 2020 at 01:11:35 UTC, Walter Bright wrote:Ok, and that's how scoped name resolution works. It's not invalid.Please elaborate on what is invalid about it? Don't make me guess!Because std.file is imported locally, the call to write calls std.file.write instead of std.stdio.write, and overwrites important_data.txt.If `import std.file` is moved to module scope, the compiler correctly diagnoses that the call is ambiguous.Yes. This is why I asked, as I wondered if I was missing something.
Nov 20 2020
On 18.11.20 02:11, Walter Bright wrote:On 11/15/2020 6:24 AM, Timon Gehr wrote:There is no collision with proper overload resolution. The error is spurious.Straw man.Doing "import std;" is just asking for trouble. I argued against it for years, and yet it was slipped in a few months ago without my knowledge. Having everything in Phobos in scope is just causing trouble. For just one of the problems, it prevents adding new modules to Phobos as it can break existing code. For another, it turns the world's fastest compiler into a pig. The example given was another example of why it's a bad idea, as the more names there are the more the likelihood of a collision. ...I'm not so sure, it's likely that one would import both std.stdio and std.file as in my example below.I think it's safe to say that the snippet was written to illustrate a point and to focus on anything else to the detriment of a discussion of that point is just deflection.Teoh would have never run into this issue if he hadn't used import std;I don't blame Teoh, a user should expect that import std; should not cause problems although the problems are inevitable. It should NEVER have been added to Phobos. ...It's useful for scripting and, apparently, for exposing bugs in name lookup and overload resolution.I don't think that's what happened in this case. There is the original simple, sound, easy to explain import scheme, but for mysterious reasons it was _never applied_ to nested imports. Why not? What kinds of special cases have been added, by the way?If the language was working properly, the code would compile and run fine. There is a hole in the design of the language here. There's no need to prioritize this particular issue, but I don't understand why you don't just acknowledge that this is not how the compiler should behave in this situation.Frankly, I don't know how the compiler should behave. The original import scheme was simple, sound, and easy to explain, but everyone complained it wasn't "intuitive" and put in a complex scheme full of special cases. Complex special cases produce an endless stream of unanticipated special cases. ...Altering how the compiler does lookups now, regardless of how it "should" behave, could break existing code in mysterious ways. Especially if one imports every symbol in existence into a local scope :-( ...I think that's not true in this case. (As I know you are aware, hijacking protection is designed precisely to avoid breaking code in mysterious ways!)It's a prototypical example of symbol hijacking. std.file.write hides std.stdio.write. Therefore, the code above overwrites the contents of the file "important_data.txt" with the string " read sucessfully!\n". The code should result in an ambiguity error as there are matches in two distinct overload sets. I think it's explained in the issue I linked.It's not just rejects-valid either, this issue has accepts-invalid cases: --- import std.stdio; string readAndLog(string filename){ import std.file; auto text=readText(filename); write(filename," read successfully!\n"); return text; } void main(){ writeln(readAndLog("important_data.txt")); } ---Please elaborate on what is invalid about it? Don't make me guess!
Nov 17 2020
On 11/17/2020 5:28 PM, Timon Gehr wrote:On 18.11.20 02:11, Walter Bright wrote:Reasonable people can disagree over what "proper" overload resolution is.On 11/15/2020 6:24 AM, Timon Gehr wrote:There is no collision with proper overload resolution. The error is spurious.What kinds of special cases have been added, by the way?I don't remember the details, it was several years ago. And the fact that I don't recall the details suggests it is more complex than necessary. I was aiming for something better than C++ where perhaps 1 in 10,000 C++ programmers can actually explain why one symbol is preferred over another, the other 9,999 just try random things until they get what they want. That I've failed at that is disappointing. But I also know that endlessly tweaking it to find the "proper" solution means endlessly breaking existing code in mysterious ways.I think that's not true in this case. (As I know you are aware, hijacking protection is designed precisely to avoid breaking code in mysterious ways!)And it's been mostly successful at that. But even if it isn't, suddenly breaking existing code doesn't please users.That isn't hijacking, it's scoping. Hijacking is when an overload is added to one module that is accidentally a better match than unrelated overloads in another module, when both are in the same scope.Please elaborate on what is invalid about it? Don't make me guess!It's a prototypical example of symbol hijacking. std.file.write hides std.stdio.write. Therefore, the code above overwrites the contents of the file "important_data.txt" with the string " read sucessfully!\n". The code should result in an ambiguity error as there are matches in two distinct overload sets.
Nov 20 2020
On Fri, Nov 20, 2020 at 06:25:59PM -0800, Walter Bright via Digitalmars-d wrote:On 11/17/2020 5:28 PM, Timon Gehr wrote:[...]The problem is that this concept of scoping is very counterintuitive: object.get is (implicitly) imported at module scope. Then std.curl.get is imported in function scope. When `get` is referenced, std.curl.get gets tried first, which is expected. But failing that (because the arguments don't match std.curl.get), one expects the compiler to fallback to the parent scope and try object.get, since, after all, the arguments obviously don't match std.curl.get, the user probably meant to call a different `get` that's in scope. However, the compiler bails out with an error instead. The overall appearance is, std.curl.get has hijacked object.get. It may not *technically* be hijacking, but it certainly looks like it, feels like it, and smells like it. T -- Democracy: The triumph of popularity over principle. -- C.BondIt's a prototypical example of symbol hijacking. std.file.write hides std.stdio.write. Therefore, the code above overwrites the contents of the file "important_data.txt" with the string " read sucessfully!\n". The code should result in an ambiguity error as there are matches in two distinct overload sets.That isn't hijacking, it's scoping. Hijacking is when an overload is added to one module that is accidentally a better match than unrelated overloads in another module, when both are in the same scope.
Nov 21 2020
On 21.11.20 03:25, Walter Bright wrote:You can have three modules where module `A` imports module `B` and `C` and if I add a symbol `foo` in module C, some lookup in `A` changes from `B.foo` to `C.foo`. I'd call that hijacking: You have a relationship between modules `A` and `B` that is intruded upon by some unrelated change in module `C`. (Anyway, my point was actually that this is bad, not that it should be called hijacking. It's even bad for the same reason "overload" hijacking is bad.)That isn't hijacking, it's scoping. Hijacking is when an overload is added to one module that is accidentally a better match than unrelated overloads in another module, when both are in the same scope.It's a prototypical example of symbol hijacking. std.file.write hides std.stdio.write. Therefore, the code above overwrites the contents of the file "important_data.txt" with the string " read sucessfully!\n". The code should result in an ambiguity error as there are matches in two distinct overload sets.
Nov 21 2020
On Friday, 13 November 2020 at 22:57:03 UTC, H. S. Teoh wrote:Just ran into this today: void main() { int[string] aa; int x; x = aa.get("abc", 123); // OK import std; x = aa.get("abc", 123); // Error: template std.net.curl.get cannot deduce function from argument types ... import std, object; x = aa.get("abc", 123); // OK } I know there's technically an explanation of this in terms of how the compiler implements import, but seriously, this is extremely annoying and confusing behaviour. Especially because the symbol being hijacked comes from the implicitly-imported object.d. Newbies wouldn't even *know* where to look if they encountered this error. D's import implementation was supposed to be designed to prevent symbol hijacking, but in this case it's falling flat on its face. Why can't we make it so that symbols that aren't explicitly named on the import line would add to existing overload sets instead of replacing them? TThis is why our style guide doesn't allow unqualified imports in functions. The more I think about it, the more I suspect function local imports were just a mistake to begin with. Bouncing back from module scope into import scope is just fundamentally bad for understandability. The set of relevant symbols goes from "all the ones imported" to "all the ones in the module" back to "all the ones imported" again, with imports shadowing local functions, which is exactly the opposite of what should happen. Putting aside how Walter is completely correct that "import std" was a mistake, I'd go further and also remove unqualified module imports completely. There's a set of features that are good for writing but bad for reading. Generally as time goes on, people discover those features are bad ideas, but because writing comes before reading, everyone thinks they're a good idea at first, so languages are doomed to reinvent them.
Nov 18 2020
On Wednesday, 18 November 2020 at 10:14:44 UTC, FeepingCreature wrote:Putting aside how Walter is completely correct that "import std" was a mistake, I'd go further and also remove unqualified module imports completely. There's a set of features that are good for writing but bad for reading. Generally as time goesIs it possible to imply an import by fully qualifying the path? E.g. ::statistics.stddev(numberslist)
Nov 18 2020
On 18.11.20 11:14, FeepingCreature wrote:On Friday, 13 November 2020 at 22:57:03 UTC, H. S. Teoh wrote:The shadowing is bad, not local imports...Just ran into this today: void main() { int[string] aa; int x; x = aa.get("abc", 123); // OK import std; x = aa.get("abc", 123); // Error: template std.net.curl.get cannot deduce function from argument types ... import std, object; x = aa.get("abc", 123); // OK } I know there's technically an explanation of this in terms of how the compiler implements import, but seriously, this is extremely annoying and confusing behaviour. Especially because the symbol being hijacked comes from the implicitly-imported object.d. Newbies wouldn't even *know* where to look if they encountered this error. D's import implementation was supposed to be designed to prevent symbol hijacking, but in this case it's falling flat on its face. Why can't we make it so that symbols that aren't explicitly named on the import line would add to existing overload sets instead of replacing them? TThis is why our style guide doesn't allow unqualified imports in functions. The more I think about it, the more I suspect function local imports were just a mistake to begin with. Bouncing back from module scope into import scope is just fundamentally bad for understandability. The set of relevant symbols goes from "all the ones imported" to "all the ones in the module" back to "all the ones imported" again, with imports shadowing local functions, which is exactly the opposite of what should happen. ...Putting aside how Walter is completely correct that "import std" was a mistake, I'd go further and also remove unqualified module imports completely. There's a set of features that are good for writing but bad for reading. Generally as time goes on, people discover those features are bad ideas, but because writing comes before reading, everyone thinks they're a good idea at first, so languages are doomed to reinvent them.I'd hate that. It would make D less viable for writing small scripts. If you are actively wondering, it's trivially easy to figure out where a symbol came from, and listing all imported symbols screws with reading as well as writing. (It's just bloat, nobody would actually look at the list, except when wondering where some specific symbol came from). The compiler should just ensure that there are no surprises, i.e., anti-hijacking is enough. If it makes sense to enforce additional style guidelines in your own code base, that's simple to do too, no need to break everyone else's code for no benefit.
Nov 18 2020
On Wed, Nov 18, 2020 at 10:14:44AM +0000, FeepingCreature via Digitalmars-d wrote: [...]This is why our style guide doesn't allow unqualified imports in functions. The more I think about it, the more I suspect function local imports were just a mistake to begin with. Bouncing back from module scope into import scope is just fundamentally bad for understandability. The set of relevant symbols goes from "all the ones imported" to "all the ones in the module" back to "all the ones imported" again, with imports shadowing local functions, which is exactly the opposite of what should happen.There are several factors at work here. Local imports are good in the sense that you minimize namespace pollution: import the symbol only where you need them, not anywhere else. They are also good for encapsulation: cut and paste your function into another module, and it Just Works. Whereas if it depended on symbols imported at the module level, you now have to copy-n-paste that import into the new module. And we all know what happens to that blob of imports at the top of the file: it just keeps growing and growing, and nobody dares delete it because you don't know what else might depend on it. (Well, theoretically it's easy, just delete them one by one and put back whichever causes a compile error. In practice, though, that's too much work just for deleting a line of code, so nobody does it.) The problems come from *unqualified* local imports, and on this point I agree with you that unqualified local imports are generally a bad idea. We've known of this since a long time ago, actually: void fun(string text) { import std.conv; writeln(text); } void main() { fun("hello world"); } This (used to) output a blank line, because `text` got hijacked by std.conv.text. IIRC somebody subsequently merged a DMD PR to change the lookup rules to fix this case. I thought that PR solved the problem somehow, but as Walter said, it led to one special case after another. And now here we are.Putting aside how Walter is completely correct that "import std" was a mistake, I'd go further and also remove unqualified module imports completely. There's a set of features that are good for writing but bad for reading. Generally as time goes on, people discover those features are bad ideas, but because writing comes before reading, everyone thinks they're a good idea at first, so languages are doomed to reinvent them.I don't agree that `import std` is a mistake. It's a wonderful shortcut for one-off scripts and `echo ... | dmd -` one-liners. Having to explicitly spell out individual Phobos modules would completely kill the latter usage because it becomes too onerous an effort for something that's meant to be a one-time quick hack. In fact, even in larger programs I think `import std` is a net plus, because as somebody has already said, who really cares about that blob of imports at the top of the file spelling out individual Phobos modules? Nobody reads it, and nobody cares except to satisfy the compiler. I can understand if you're importing some 3rd party library and the compiler needs to be told where to find those symbols, but this is the *standard* library, darnit. It's supposed to be standard symbols common across all D programs (more or less). Having to spell that out every single time I use it is just Java-style needless boilerplate. But I do agree that unqualified `import std` as a local import is a bad idea, since it pulls in a whole truckload of symbols that, in all likelihood, will clash with / shadow local symbols. As I said, in general unqualified local imports are bad news, because you don't know what symbols might get pulled in; a local symbol can easily get hijacked by a new symbol added to some 3rd party dependency. Though I have to say, even despite the landmines, local `import std` is useful for inserting temporary one-off debug code into otherwise import-clean code. I often insert `import std; stderr.writefln("debug info");` into strategic points in my code while debugging. It gives you instant access to regular Phobos algorithms and functions without the tedium of painstakingly spelling out every module you might need. And it's temporary and fits on one line, so it's just as easy to delete afterwards without polluting the rest of the code. So love it or hate it, `import std` *does* have its uses. In this particular instance of problems caused by it, my opinion is leaning towards std.curl.get being poorly-named. HTTP GET is a rather narrow and specific function, as opposed to object.get for AA's which are built into the language. If it weren't for that ever-looming spectre of breaking existing code, I'd say rename it to something else. Like curlGet or something. T -- First Rule of History: History doesn't repeat itself -- historians merely repeat each other.
Nov 18 2020
On Wednesday, 18 November 2020 at 18:10:58 UTC, H. S. Teoh wrote:Local imports are good in the sense that you minimize namespace pollution: import the symbol only where you need them, not anywhere else.They are also good for encapsulation: cut and paste your function into another module, and it Just Works. Whereas if it depended on symbols imported at the module level, you now have to copy-n-paste that import into the new module. And we all know what happens to that blob of imports at the top of the file: it just keeps growing and growing, and nobody dares delete it because you don't know what else might depend on it.Yes that's true, but on the other hand you will need to duplicate or repeat yourself with local imports, like: void bar(){ import std.stdio; writeln("bar"); } void foo(){ import std.stdio; writeln("foo"); } void main(string[ ] args){ foo(); bar(); } Wouldn't this generate some pollution as well as your program grows? Matheus.
Nov 18 2020
On Wednesday, 18 November 2020 at 18:10:58 UTC, H. S. Teoh wrote:In this particular instance of problems caused by it, my opinion is leaning towards std.curl.get being poorly-named. HTTP GET is a rather narrow and specific function, as opposed to object.get for AA's which are built into the language. If it weren't for that ever-looming spectre of breaking existing code, I'd say rename it to something else. Like curlGet or something.std.curl.get is absolutely not at fault here. The whole point of modules (and namespaces in general) is that you can use whatever names you want in them without having to worry about conflicts. And if you need to use two different `get`s in the same scope, D has plenty of tools to help you disambiguate: import curl = std.curl; // ... curl.get(whatever); import std.curl; alias curlGet = std.curl.get; // ... curlGet(whatever); static import std.curl; // ... std.curl.get(whatever);
Nov 18 2020
On Wednesday, 18 November 2020 at 10:14:44 UTC, FeepingCreature wrote:This is why our style guide doesn't allow unqualified imports in functions. The more I think about it, the more I suspect function local imports were just a mistake to begin with.No way, they are correctness and performance feature. Look at STL to see what happens when everything is visible.
Nov 18 2020
On Wednesday, 18 November 2020 at 21:13:00 UTC, Kagamin wrote:On Wednesday, 18 November 2020 at 10:14:44 UTC, FeepingCreature wrote:I think the problem with C++ is more transitive imports than file-level imports. Or rather, the lack of a module system.This is why our style guide doesn't allow unqualified imports in functions. The more I think about it, the more I suspect function local imports were just a mistake to begin with.No way, they are correctness and performance feature. Look at STL to see what happens when everything is visible.
Nov 19 2020
On Friday, 13 November 2020 at 22:57:03 UTC, H. S. Teoh wrote:D's import implementation was supposed to be designed to prevent symbol hijacking, but in this case it's falling flat on its face. Why can't we make it so that symbols that aren't explicitly named on the import line would add to existing overload sets instead of replacing them? TWouldn't *that* allow hijacking? Unless of course you remove implicit conversions of parameters. If you have a `void foo(short)` in a module, and you're using it from your main like so: `foo(42);`, then suddenly, if overload sets were merged, another import at the same level could introduce `void foo(int)`, which would be a better match, and hijack the call, instead of creating an error as done currently.
Nov 18 2020
On 18.11.20 17:23, Mathias LANG wrote:On Friday, 13 November 2020 at 22:57:03 UTC, H. S. Teoh wrote:How it should work: - Do a lookup in the current module. - If name is not found, figure out which (possibly nested) imports are in scope. - Use the same standard overload resolution that is used for module-scope imports on those imports.D's import implementation was supposed to be designed to prevent symbol hijacking, but in this case it's falling flat on its face. Why can't we make it so that symbols that aren't explicitly named on the import line would add to existing overload sets instead of replacing them? TWouldn't *that* allow hijacking? Unless of course you remove implicit conversions of parameters. If you have a `void foo(short)` in a module, and you're using it from your main like so: `foo(42);`, then suddenly, if overload sets were merged, another import at the same level could introduce `void foo(int)`, which would be a better match, and hijack the call, instead of creating an error as done currently.
Nov 18 2020
On Wed, Nov 18, 2020 at 10:12:25PM +0100, Timon Gehr via Digitalmars-d wrote: [...]How it should work: - Do a lookup in the current module. - If name is not found, figure out which (possibly nested) imports are in scope. - Use the same standard overload resolution that is used for module-scope imports on those imports.+1, this is the way it should have been from the beginning. T -- Why are you blatanly misspelling "blatant"? -- Branden Robinson
Nov 18 2020
On Friday, 13 November 2020 at 22:57:03 UTC, H. S. Teoh wrote:Just ran into this today: void main() { int[string] aa; int x; x = aa.get("abc", 123); // OK import std; x = aa.get("abc", 123); // Error: template std.net.curl.get cannot deduce function from argument types ... import std, object; x = aa.get("abc", 123); // OK }Can we fix this particular case by adding "public import object;" to std/package.d ?
Nov 20 2020