www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Does dmd not always compile all of the source code?

reply A Guy With a Question <aguywithanquestion gmail.com> writes:
Noticed several typos that dmd seems to have not picked up 
initially. Does dmd not compile all source code? I obviously 
wouldn't expect it to recompile something unnecessarily, but in a 
few cases I've just seen it not throw errors where it should have.
Dec 06 2017
next sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Wednesday, 6 December 2017 at 16:07:41 UTC, A Guy With a 
Question wrote:
 Noticed several typos that dmd seems to have not picked up 
 initially. Does dmd not compile all source code? I obviously 
 wouldn't expect it to recompile something unnecessarily, but in 
 a few cases I've just seen it not throw errors where it should 
 have.
It depends on how you're invoking it. In all likelihood, you had typos in uninstantiated templates. Atila
Dec 06 2017
parent reply A Guy With a Question <aguywithanquestion gmail.com> writes:
On Wednesday, 6 December 2017 at 16:10:34 UTC, Atila Neves wrote:
 On Wednesday, 6 December 2017 at 16:07:41 UTC, A Guy With a 
 Question wrote:
 Noticed several typos that dmd seems to have not picked up 
 initially. Does dmd not compile all source code? I obviously 
 wouldn't expect it to recompile something unnecessarily, but 
 in a few cases I've just seen it not throw errors where it 
 should have.
It depends on how you're invoking it. In all likelihood, you had typos in uninstantiated templates. Atila
I'm not sure how it works underneath the covers, but I'm not currently working with a ton of templates explicitly. I am utilizing interfaces and some generic container types, which I guess might mean templates underneath. However, if an abstract class with a generic parameter translates itself to a template underneath the covers, I still would expect it to throw an error if I have a clear syntax problem. If it's not, that's pretty unacceptable actually for it not to.
Dec 06 2017
parent reply A Guy With a Question <aguywithanquestion gmail.com> writes:
I have to be honest, I'm a little worried about all of this code 
I just translated and how much of it is actually valid...I hope I 
didn't waste my time.
Dec 06 2017
parent reply A Guy With a Question <aguywithanquestion gmail.com> writes:
On Wednesday, 6 December 2017 at 16:32:05 UTC, A Guy With a 
Question wrote:
 I have to be honest, I'm a little worried about all of this 
 code I just translated and how much of it is actually valid...I 
 hope I didn't waste my time.
Ok, so I verified this much. I would expect an error from the following, but it does not actually produce an error... module grrr.grr; abstract class Test(T) { private: T thing; public: this(T theThing) { thing = theThing; thisdoesnotexist(); // expect compiler error right here!!!! } } ...but this compiles just fine.
Dec 06 2017
next sibling parent reply A Guy With a Question <aguywithanquestion gmail.com> writes:
On Wednesday, 6 December 2017 at 16:47:17 UTC, A Guy With a 
Question wrote:
 On Wednesday, 6 December 2017 at 16:32:05 UTC, A Guy With a 
 Question wrote:
 I have to be honest, I'm a little worried about all of this 
 code I just translated and how much of it is actually 
 valid...I hope I didn't waste my time.
Ok, so I verified this much. I would expect an error from the following, but it does not actually produce an error... module grrr.grr; abstract class Test(T) { private: T thing; public: this(T theThing) { thing = theThing; thisdoesnotexist(); // expect compiler error right here!!!! } } ...but this compiles just fine.
It does produce there error when I do this: class Test2 : Test!int { this(int thing) { super(thing); } }
Dec 06 2017
parent reply A Guy With a Question <aguywithanquestion gmail.com> writes:
On Wednesday, 6 December 2017 at 16:49:51 UTC, A Guy With a 
Question wrote:
 module grrr.grr;

 abstract class Test(T)
 {
 private:
     T thing;

 public:
     this(T theThing)
     {
         thing = theThing;
 	thisdoesnotexist(); // expect compiler error right here!!!!
     }
 }

 ...but this compiles just fine.
It does produce there error when I do this: class Test2 : Test!int { this(int thing) { super(thing); } }
Another example: interface ITest(T) { property Nullable!T value(); // have not imported Nullable. Should fail. } compiles... Fails when this happens: class Test : ITest!int { property Nullable!int value() { return nullable(0); } } I really do think, regardless of if this is considered a template expansion, that dmd should be catching these obvious errors. When one writes interfaces and abstract classes they are generally not ready to implement the end class yet. And getting a ton of errors at once when that occurs is really hard to deal with. I really don't understand why the compiler would have issues with this.
Dec 06 2017
next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/6/17 12:04 PM, A Guy With a Question wrote:

 I really do think, regardless of if this is considered a template 
 expansion, that dmd should be catching these obvious errors. When one 
 writes interfaces and abstract classes they are generally not ready to 
 implement the end class yet. And getting a ton of errors at once when 
 that occurs is really hard to deal with. I really don't understand why 
 the compiler would have issues with this.
So, it is important to note that a template must successfully *parse*, but it cannot be semantically analyzed until it is instantiated. It is no different from C++ templates. So why wouldn't the compiler fail? Because it has no idea yet what you mean by Nullable. It doesn't even know if Nullable will be available or not. You could even import Nullable, but Nullable!T may be an error. This is definitely different from Generics (which I think you are familiar with), where there is some semblance of structure implied in the wildcard types. With templates, the type can be anything. It might be possible to do some deduction of whether something will EVER compile, but it's probably not worth the extra work. Did you waste your time? No. It seems like all your errors are simple import problems, just fix the bugs, and you should be good! For the future, the correct way to write templates like this is to instantiate them in tests. Use unittesting, and you shouldn't have problems like this. -Steve
Dec 06 2017
parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/6/17 12:17 PM, Steven Schveighoffer wrote:

 So why wouldn't the compiler fail? Because it has no idea yet what you 
 mean by Nullable. It doesn't even know if Nullable will be available or 
 not. You could even import Nullable, but Nullable!T may be an error.
To give an example of why the compiler waits until instantiation: class C(T) : T { void foo() { doesthisexist(); } } class D { void doesthisexist(); } auto x = new C!D; // OK auto y = new C!Object: // fail -Steve
Dec 06 2017
parent reply A Guy With a Question <aguywithanquestion gmail.com> writes:
On Wednesday, 6 December 2017 at 18:09:45 UTC, Steven 
Schveighoffer wrote:
 On 12/6/17 12:17 PM, Steven Schveighoffer wrote:

 So why wouldn't the compiler fail? Because it has no idea yet 
 what you mean by Nullable. It doesn't even know if Nullable 
 will be available or not. You could even import Nullable, but 
 Nullable!T may be an error.
To give an example of why the compiler waits until instantiation: class C(T) : T { void foo() { doesthisexist(); } } class D { void doesthisexist(); } auto x = new C!D; // OK auto y = new C!Object: // fail -Steve
It also doesn't parse or do semantic checks on unit tests unless you add the flag...apparently. This compiles... unittest { WHY DOESNT THE COMPILER FIND A PROBLEM HERE!? } It seems D's fast compile times are achieved by skipping semantic checking and even parsing when it doesn't feel it's needed. I strongly disagree with this decision. This could leave complex dormant time bombs that break builds unexpectedly and even accidentally. It's understandable in certain situations where there is enough information, but the first step to testing code, is first making sure it compiles...I don't want the compiler making decisions on what is worthy to compile. If I pass a d source file into it, I want to know if it's valid. This is unfortunate. This might be a deal breaker for me.
Dec 06 2017
next sibling parent reply A Guy With a Question <aguywithanquestion gmail.com> writes:
On Wednesday, 6 December 2017 at 19:19:09 UTC, A Guy With a 
Question wrote:
 It seems D's fast compile times are achieved by skipping 
 semantic checking and even parsing when it doesn't feel it's 
 needed. I strongly disagree with this decision. This could 
 leave complex dormant time bombs that break builds unexpectedly 
 and even accidentally. It's understandable in certain 
 situations where there is enough information, but the first 
 step to testing code, is first making sure it compiles...I 
 don't want the compiler making decisions on what is worthy to 
 compile. If I pass a d source file into it, I want to know if 
 it's valid. This is unfortunate. This might be a deal breaker 
 for me.
I'm very concerned of working with a language that, at minimum, doesn't let me know if a file I passed in even contains valid code.
Dec 06 2017
parent Atila Neves <atila.neves gmail.com> writes:
On Wednesday, 6 December 2017 at 19:40:49 UTC, A Guy With a 
Question wrote:
 On Wednesday, 6 December 2017 at 19:19:09 UTC, A Guy With a 
 Question wrote:
 It seems D's fast compile times are achieved by skipping 
 semantic checking and even parsing when it doesn't feel it's 
 needed. I strongly disagree with this decision. This could 
 leave complex dormant time bombs that break builds 
 unexpectedly and even accidentally. It's understandable in 
 certain situations where there is enough information, but the 
 first step to testing code, is first making sure it 
 compiles...I don't want the compiler making decisions on what 
 is worthy to compile. If I pass a d source file into it, I 
 want to know if it's valid. This is unfortunate. This might be 
 a deal breaker for me.
I'm very concerned of working with a language that, at minimum, doesn't let me know if a file I passed in even contains valid code.
It does let you know if it contains valid code - if you're actually building it. If you write unit tests but never compile them in, whether or not they make any sense is IMHO irrelevant. If you write a template and never instantiate it, does it make a sound?* Imagine this: version(Windows) int i = 0; else foobarbaz; Should it fail to compile on Linux? How is this any different from: #ifdef _WIN32 int i = 0; #else ohnoes #endif As noted by others, C++ templates work similarly. And for good reason! Atila * https://en.wikipedia.org/wiki/If_a_tree_falls_in_a_forest
Dec 06 2017
prev sibling next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 12/6/17 2:19 PM, A Guy With a Question wrote:
 On Wednesday, 6 December 2017 at 18:09:45 UTC, Steven Schveighoffer wrote:
 On 12/6/17 12:17 PM, Steven Schveighoffer wrote:

 So why wouldn't the compiler fail? Because it has no idea yet what 
 you mean by Nullable. It doesn't even know if Nullable will be 
 available or not. You could even import Nullable, but Nullable!T may 
 be an error.
To give an example of why the compiler waits until instantiation: class C(T) : T {    void foo() { doesthisexist(); } } class D { void doesthisexist(); } auto x = new C!D; // OK auto y = new C!Object: // fail -Steve
It also doesn't parse or do semantic checks on unit tests unless you add the flag...apparently. This compiles... unittest {     WHY DOESNT THE COMPILER FIND A PROBLEM HERE!? } It seems D's fast compile times are achieved by skipping semantic checking and even parsing when it doesn't feel it's needed.
This is a red herring. The compile times are fast even with unittests enabled. They are just faster (and use less memory) when unittests aren't compiled in. If a unit test is instantiating tons of templates that I'm not using in my main code, I don't want that being compiled and then thrown away when I don't care about it!
 I strongly 
 disagree with this decision. This could leave complex dormant time bombs 
 that break builds unexpectedly and even accidentally. 
This decision was made by reality. How do you compile incomplete code? that is essentially what a template is. In terms of unit tests that don't compile, I can't ever imagine someone writing a unittest and then not compiling with -unittest, and being upset their code "passed". Note, this was done pretty recently, and simply to make the compiler consume less memory (and run a bit faster).
 It's 
 understandable in certain situations where there is enough information, 
 but the first step to testing code, is first making sure it compiles...I 
 don't want the compiler making decisions on what is worthy to compile.
The first step to testing code is writing tests. And the idea that the compiler is making these decisions arbitrarily is incorrect. You are telling the compiler how to compile.
 If I pass a d source file into it, I want to know if it's valid. This is 
 unfortunate. This might be a deal breaker for me.
There is literally only one exception to the rule, unittests. Everything else must be valid syntax-wise. Even version statements must have valid syntax inside them. Hardly a deal-breaker, since you aren't going to write unittests and then not run them. -Steve
Dec 06 2017
prev sibling parent user1234 <user1234 12.nl> writes:
On Wednesday, 6 December 2017 at 19:19:09 UTC, A Guy With a 
Question wrote:
 On Wednesday, 6 December 2017 at 18:09:45 UTC, Steven 
 Schveighoffer wrote:
 On 12/6/17 12:17 PM, Steven Schveighoffer wrote:

 So why wouldn't the compiler fail? Because it has no idea yet 
 what you mean by Nullable. It doesn't even know if Nullable 
 will be available or not. You could even import Nullable, but 
 Nullable!T may be an error.
To give an example of why the compiler waits until instantiation: class C(T) : T { void foo() { doesthisexist(); } } class D { void doesthisexist(); } auto x = new C!D; // OK auto y = new C!Object: // fail -Steve
It also doesn't parse or do semantic checks on unit tests unless you add the flag...apparently. This compiles... unittest { WHY DOESNT THE COMPILER FIND A PROBLEM HERE!? } It seems D's fast compile times are achieved by skipping semantic checking and even parsing when it doesn't feel it's needed. I strongly disagree with this decision. This could leave complex dormant time bombs that break builds unexpectedly and even accidentally.
That's why measuring the level of coverage obtained by the unittests is important. It's not just about the templates, standard if conditions that are never tested can also be time bombs, standard functions that are never tested can also be time bombs. Even more pernicious in a way.
Dec 07 2017
prev sibling parent Nick Treleaven <nick geany.org> writes:
On Wednesday, 6 December 2017 at 17:04:06 UTC, A Guy With a 
Question wrote:
 abstract class Test(T)
Here you have a class template.
 It does produce there error when I do this:

 class Test2
    : Test!int
You instantiated the template, so the compiler can now type check the instantiated class.
 class Test
    : ITest!int
Same thing here but with an interface template.
 I really do think, regardless of if this is considered a 
 template expansion, that dmd should be catching these obvious 
 errors. When one writes interfaces and abstract classes they 
 are generally not ready to implement the end class yet. And 
 getting a ton of errors at once when that occurs is really hard 
 to deal with. I really don't understand why the compiler would 
 have issues with this.
I sympathize, something like Rust's traits or concept-enhanced C++ could probably do what you want, but D doesn't have this feature.
Dec 06 2017
prev sibling parent Gary Willoughby <dev nomad.so> writes:
On Wednesday, 6 December 2017 at 16:47:17 UTC, A Guy With a 
Question wrote:
 abstract class Test(T)
 {
 private:
     T thing;

 public:
     this(T theThing)
     {
         thing = theThing;
 	thisdoesnotexist(); // expect compiler error right here!!!!
     }
 }

 ...but this compiles just fine.
It's because it's not being used in your program. How can the compiler compile it without knowing what T would be? When you do this:
 class Test2
    : Test!int
 {
     this(int thing)
     {
 	super(thing);
     }
 }
You are suppling T and now it is compiled and an error raised.
Dec 06 2017
prev sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 6 December 2017 at 16:07:41 UTC, A Guy With a 
Question wrote:
 Does dmd not compile all source code?
It doesn't. I like to build with a few different options to explicitly test (e.g. build for Windows and Linux and -m32 and -m64 to ensure those all exercised) and for templates, do a -unittest that actually runs it - e.g. instantiate Array!int - to make sure that works and compile with -unittest every so often too. Might also do a `__traits(compiles` or static assert on it too. Others have explained why this is, but this is a simple way to ensure it compiles at least in some cases to catch typos like this. Another worry btw: the opDispatch feature will just say `no such property` if it fails to compile its innards. A test might also want to call it explicitly to force error messages.
Dec 07 2017