Jump to page: 1 2 3
Thread overview
Pathological import symbol shadowing
Nov 13, 2020
H. S. Teoh
Nov 14, 2020
Timon Gehr
Nov 14, 2020
Kagamin
Nov 14, 2020
Paul Backus
Nov 14, 2020
Kagamin
Nov 14, 2020
Paul Backus
Nov 15, 2020
Walter Bright
Nov 15, 2020
Timon Gehr
Nov 18, 2020
Walter Bright
Nov 18, 2020
Paul Backus
Nov 21, 2020
Walter Bright
Nov 18, 2020
Timon Gehr
Nov 21, 2020
Walter Bright
Nov 21, 2020
H. S. Teoh
Nov 22, 2020
Timon Gehr
Nov 18, 2020
FeepingCreature
Nov 18, 2020
Timon Gehr
Nov 18, 2020
Kagamin
Nov 19, 2020
FeepingCreature
Nov 18, 2020
Mathias LANG
Nov 18, 2020
Timon Gehr
Nov 19, 2020
H. S. Teoh
Nov 21, 2020
Vladimir Panteleev
November 13, 2020
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.
November 14, 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=17589


> 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?
> 

It should just use the standard import rules with overload sets. Then the code above would just work and no hijacking would be possible.
November 14, 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.
November 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:
>> 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.

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-sets
November 14, 2020
On Saturday, 14 November 2020 at 14:43:16 UTC, Paul Backus wrote:
> [1] https://dlang.org/spec/function.html#overload-sets

Ah, 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.
November 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:
>> [1] https://dlang.org/spec/function.html#overload-sets
>
> Ah, 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.

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).
November 15, 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.

November 15, 2020
On 15.11.20 10:06, Walter Bright wrote:
> 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.
> 

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"));
}
---
November 17, 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!
November 18, 2020
On Wednesday, 18 November 2020 at 01:11:35 UTC, Walter Bright wrote:
>> 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!

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.
« First   ‹ Prev
1 2 3