Thread overview | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
January 19, 2021 isCallable fails | ||||
---|---|---|---|---|
| ||||
What could cause the following error? Error: expression isCallable!(data) of type void does not have a boolean value Problematic lines are: // T = some class // S = "data" (data is member of T) // typeof(S) = some struct U!X, not void alias S = __traits(getMember, T, property); static if (isCallable!S) { // some other magic } So, struct U has an "alias this", not causing any problems except if it calls the getter on type X: struct U(T) { T get() { static if (is(T : X)) { if (value is null) { // load value } } return value; } T value; alias get this; } I do not understand why this can affect isCallable as it does nothing special. It also compiles if I remove the loading "static if" switch. |
January 19, 2021 Re: isCallable fails | ||||
---|---|---|---|---|
| ||||
Posted in reply to frame | I may know the answer but I can't be sure because you don't provide code that reproduces the issue. I am trying to write code below according to your description but it's really tough. Can you reproduce the issue please. // T = some class // T is not a good name because it is usually used template parameters class T { static U!int data = 42; } // S = "data" (data is member of T) auto S = T.data; // typeof(S) = some struct U!X, not void // WAIT! Another S? You're asking for trouble. :D alias S = __traits(getMember, T, property); static if (isCallable!S) { // some other magic } // WAIT! So, this is U? struct U(T) { T get() { static if (is(T : X)) { if (value is null) { // load value } } return value; } T value; alias get this; } void main() { } Ali |
January 20, 2021 Re: isCallable fails | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Wednesday, 20 January 2021 at 01:07:15 UTC, Ali Çehreli wrote:
> I may know the answer but I can't be sure because you don't provide code that reproduces the issue.
>
> I am trying to write code below according to your description but it's really tough. Can you reproduce the issue please.
>
> // T = some class
> // T is not a good name because it is usually used template
ok, sorry my bad - I have just shortend the code, the first part is from a template indeed:
void something(T, string property)() {
// in THIS context is T a class
// property = "data"
alias S = __traits(getMember, T, property);
// typeof(S) = foo!bar
static if (isCallable!S) {
// some other magic
}
// ...
}
And struct of course, has another identfier:
struct foo(T) {
T get() {
static if (is(T : bar)) {
if (value is null) {
value = fun!T;
}
}
return value;
}
}
There are other properties with foo!T and they are working as expected. The problem occurs if I want to assign value = fun!T.
|
January 20, 2021 Re: isCallable fails | ||||
---|---|---|---|---|
| ||||
Posted in reply to frame | On Wednesday, 20 January 2021 at 04:43:12 UTC, frame wrote:
> struct foo(T) {
> T get() {
> static if (is(T : bar)) {
> if (value is null) {
> value = fun!T;
Error: template instance `fun!T` template `fun` is not defined
Please post an example with enough code to actually produce the error you're seeing.
|
January 20, 2021 Re: isCallable fails | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | On Wednesday, 20 January 2021 at 13:11:09 UTC, Paul Backus wrote: > On Wednesday, 20 January 2021 at 04:43:12 UTC, frame wrote: >> struct foo(T) { >> T get() { >> static if (is(T : bar)) { >> if (value is null) { >> value = fun!T; > > Error: template instance `fun!T` template `fun` is not defined > > Please post an example with enough code to actually produce the error you're seeing. I don't know when to stop posting code then :( fun!T just returns bar or null. Manually calling works. but if it helps, here is fun!T: TDobj fun(TDobj, T)(string propertyName, T needle) if (is(TDobj : bar)) { TDobj[] list = loadAllMatched!TDobj(propertyName, needle, 1); return list.length > 0 ? list[0] : null; } and actually called value = fun!T("id", 123)); It also compiles if value = new T |
January 20, 2021 Re: isCallable fails | ||||
---|---|---|---|---|
| ||||
Posted in reply to frame | On Wednesday, 20 January 2021 at 19:01:19 UTC, frame wrote:
> It also compiles if
>
> value = new T
enum R = isCallable!S
throws:
Error: cannot infer type from template instance isCallable!(data), possible circular dependency
So that seems to be the problem. There is a circular dependency somewhere the compiler cannot resolve.
I believe it has something to do with "alias get this" so get() is parsed in this context or whatever. Any suggestions?
|
January 20, 2021 Re: isCallable fails | ||||
---|---|---|---|---|
| ||||
Posted in reply to frame | On Wednesday, 20 January 2021 at 19:01:19 UTC, frame wrote: > On Wednesday, 20 January 2021 at 13:11:09 UTC, Paul Backus >> >> Please post an example with enough code to actually produce the error you're seeing. > > I don't know when to stop posting code then :( You should stop (and ideally start) with a Minimal, Complete, Verifiable Example: https://idownvotedbecau.se/nomcve/ Just to illustrate why this matters, let me walk you through the steps it takes me to try and figure out what your issue is from just the posts you've made so far. --- Step 1: go through each of your posts and copy each of the individual code snippets into a run.dlang.io window. Result: https://run.dlang.io/is/nidfug This code compiles--because it's all templates, and you haven't actually provided any example of the code that *uses* these templates. --- Step 2: look at the comments and try to guess what the usage code must look like. Result: https://run.dlang.io/is/P7Pcr1 First, we need to define a class with a member named `data` to pass as an argument to something. And data's type has to be `foo!bar`, so we need a type named `bar` to use for that. What kind of type? Well, if we look at how `bar` is used in `foo`, we can see that it's compared with `null`, so we know it's a reference type--probably a class. Now we can finally attempt to instantiate `something`. What happens when we do? Error: template instance loadAllMatched!TDobj template loadAllMatched is not defined Great, another piece of missing code. --- Step 3: try to stub out loadAllMatched. Result: https://run.dlang.io/is/uRj6HW Error: template instance `isCallable!S` template `isCallable` is not defined Siiiiigh. --- Step 4: add the missing import. Result: https://run.dlang.io/is/2by7sU Oh, look, it compiles with no errors. All that effort, and I *still* couldn't reproduce the issue you described in your original post. Guess I wasted my time for nothing! |
January 20, 2021 Re: isCallable fails | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | On Wed, Jan 20, 2021 at 09:57:59PM +0000, Paul Backus via Digitalmars-d-learn wrote: > On Wednesday, 20 January 2021 at 19:01:19 UTC, frame wrote: > > On Wednesday, 20 January 2021 at 13:11:09 UTC, Paul Backus > > > > > > Please post an example with enough code to actually produce the error you're seeing. > > > > I don't know when to stop posting code then :( > > You should stop (and ideally start) with a Minimal, Complete, > Verifiable Example: > > https://idownvotedbecau.se/nomcve/ [...] And if you're not sure how to arrive at such an example, DustMite is one way of doing it: https://github.com/CyberShadow/DustMite/wiki --T |
January 21, 2021 Re: isCallable fails | ||||
---|---|---|---|---|
| ||||
Posted in reply to Paul Backus | On Wednesday, 20 January 2021 at 21:57:59 UTC, Paul Backus wrote:
> On Wednesday, 20 January 2021 at 19:01:19 UTC, frame wrote:
>
> Oh, look, it compiles with no errors. All that effort, and I *still* couldn't reproduce the issue you described in your original post. Guess I wasted my time for nothing!
Ok, really thank you for your effort - but I was talking about the error first (did you even read it?). I have explained that isCallable gets valid data and not void. I was asking if someone has encountered this kind of error before and can give my a hint what *could* going on.
I was not asking here to re-produce my code or debug since it cannot provide a snippet if I do not know what could cause the error.
The example code just should illustrate that isCallable is called on a valid way and "alias this" may cause the problem (as I assumed) - that's all.
Sorry, but you "wasting your time" more by unnecessarily commenting which isn't appropriate here.
--
So back to topic:
The error is a circular dependency (and no, it's not just in loadAllMatched!TDobj, it's something deeper). "alias get this" leads to parsing get() when isCallable is called. Is there any way to avoid running in this issue?
|
January 22, 2021 Re: isCallable fails | ||||
---|---|---|---|---|
| ||||
Posted in reply to frame | On Thursday, 21 January 2021 at 05:20:27 UTC, frame wrote:
> I was not asking here to re-produce my code or debug since it cannot provide a snippet if I do not know what could cause the error.
Generally, I don't need to know what causes an error in order to produce an MCVE. I have successfully done so on many occasions. It's annoying and slow, but usually very possible.
If it seems like it's going to be really difficult for a particular bug, it's fine to try asking others without an MCVE first. But, you should think of MCVE discovery as a valuable skill, not an impossibility.
My technique works like this:
0) Make note of the symptoms/message for the specific failure that I am trying to isolate.
1) Make a separate copy of the program's source code which I can freely destroy.
2) Remove, simplify, or mock up/stub out (like for unit tests) some large chunk of the remaining code in the program, from a part of the program that I *think* is unrelated to the error.
3) Re-test the program.
a) If the failure goes away, goto (2) and try again by removing a different part of the program.
b) If the failure is still present and I think there is more that could be removed or simplified, goto (2).
c) If the failure is still present, and I don't see anything else to remove or simplify, then I'm done. Whatever is left of the source code (hopefully something short and non-proprietary) is my MCVE.
It's sort of a guess-and-check binary search for the minimum code that triggers the error. This process can be quite tedious, but it often does not require already knowing the cause of the error. (dustmite is a tool that partially automates this.)
Sometimes it's worth going through, because having an MCVE is *really* useful, especially for other people who don't know the rest of your project's mostly-unrelated code base and dependencies well.
|
Copyright © 1999-2021 by the D Language Foundation