www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Bug?

reply Jack Applegame <japplegame gmail.com> writes:
Why doesn't it compile?

```
struct Range(R) {
     import std.array : empty, front, popFront;
     R range;
     bool empty() const { return range.empty; }
     auto front() const { return range.front; }
     void popFront() { range.popFront(); }
}

void main() {
     auto rng = Range!string("1234");
     assert(rng.front == 1);
}
```

onlineapp.d(11): Error: void has no value
onlineapp.d(11): Error: incompatible types for (rng.front) == 
(1): void and int

try here: https://run.dlang.io/is/Dg8Fpr

If you move the import to the global scope, you will get a weird 
result:

```
import std.stdio;
import std.array : empty, front, popFront;

struct Range(R) {
     R range;
     bool empty() const { return range.empty; }
     auto front() const { return range.front; }
     void popFront() { range.popFront(); }
}

void main() {
     auto rng = Range!string("1234");
     writefln("front: %s", rng.front);
     assert(rng.front == 1);
}
```

front: 1
core.exception.AssertError onlineapp.d(14): Assertion failure
----------------
??:? _d_assertp [0x56107489bc75]
onlineapp.d:14 _Dmain [0x561074889902]

try here: https://run.dlang.io/is/arieKR

WAT???
May 11 2020
next sibling parent reply Jack Applegame <japplegame gmail.com> writes:
On Monday, 11 May 2020 at 12:20:06 UTC, Jack Applegame wrote:
     assert(rng.front == 1);
Damn! I made a typo. It must be: assert(rng.front == '1') So the second example works fine.
May 11 2020
parent Jack Applegame <japplegame gmail.com> writes:
And the first example still doesn't compile:

```
struct Range(R) {
	import std.array : empty, front, popFront;
     R range;
     bool empty() const { return range.empty; }
     auto front() const { return range.front; }
     void popFront() { range.popFront(); }
}

void main() {
     auto rng = Range!string("1234");
     assert(rng.front == '1');
}
```

onlineapp.d(11): Error: void has no value
onlineapp.d(11): Error: incompatible types for (rng.front) == 
('1'): void and char
```
May 11 2020
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 11 May 2020 at 12:20:06 UTC, Jack Applegame wrote:
 If you move the import to the global scope
UFCS is only defined to work with global scope functions. A restricted import (module : symbol, symbols) puts things in local scope so ufcs doesn't apply. (interestingly an unrestricted import does NOT do that, it keeps the functions in their original scope, so UFCS works if you locally `import std.range;` but not if you `import std.range : front, popFront, empty;`! lol. but this is... im pretty sure by design, it has been this way for ages.)
May 11 2020
parent reply Jack Applegame <japplegame gmail.com> writes:
On Monday, 11 May 2020 at 12:30:22 UTC, Adam D. Ruppe wrote:
 UFCS is only defined to work with global scope functions. A 
 restricted import (module : symbol, symbols) puts things in 
 local scope so ufcs doesn't apply.
But in this case the error should be displayed for lines 4 and 5, not 11. Line 11 contains a call to a member function, not UFCS. In addition, if you add the parentheses, then it works: assert(rng.front() == '1');
May 11 2020
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/11/20 8:44 AM, Jack Applegame wrote:
 On Monday, 11 May 2020 at 12:30:22 UTC, Adam D. Ruppe wrote:
 UFCS is only defined to work with global scope functions. A restricted 
 import (module : symbol, symbols) puts things in local scope so ufcs 
 doesn't apply.
But in this case the error should be displayed for lines 4 and 5, not 11. Line 11 contains a call to a member function, not UFCS. In addition, if you add the parentheses, then it works: assert(rng.front() == '1');
Yeah, this is definitely a bug. If I change the return type of front to dchar from auto, it still thinks it's returning void. Calling things like popFront without parentheses has an error "rng.popFront has no effect". Clearly something isn't connecting properly, it's almost like it's resolving to the function itself instead of calling it. -Steve
May 11 2020
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Monday, 11 May 2020 at 13:06:59 UTC, Steven Schveighoffer 
wrote:
 Clearly something isn't connecting properly, it's almost like 
 it's resolving to the function itself instead of calling it.
Since the imported front is also a local symbol the compiler probably thinks it is overloaded and not handling that right.....
May 11 2020
prev sibling parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Monday, 11 May 2020 at 12:44:45 UTC, Jack Applegame wrote:
 On Monday, 11 May 2020 at 12:30:22 UTC, Adam D. Ruppe wrote:
 UFCS is only defined to work with global scope functions. A 
 restricted import (module : symbol, symbols) puts things in 
 local scope so ufcs doesn't apply.
But in this case the error should be displayed for lines 4 and 5, not 11. Line 11 contains a call to a member function, not UFCS. In addition, if you add the parentheses, then it works: assert(rng.front() == '1');
You're right, and it absolutely seems the call on lines 4 and 5 work correctly. Instead, the compiler is confused by the presence of two different overloads for front in Range!T, and doesn't attempt to call the one it can call. We get the exact same behavior here: struct S { int gun()(int i) { return 0; } alias fun = gun; int fun() { return 1; } } static assert(S().fun == 1); Filed here: https://issues.dlang.org/show_bug.cgi?id=20821 -- Simen
May 11 2020
parent Jack Applegame <japplegame gmail.com> writes:
On Monday, 11 May 2020 at 13:12:37 UTC, Simen Kjærås wrote:
 Filed here: https://issues.dlang.org/show_bug.cgi?id=20821
Thanks.
May 11 2020