Re: is ==
On Saturday, May 19, 2018 03:32:53 Neia Neutuladh via Digitalmars-d-learn wrote: > > Of course, the most notable case where using == with null is a > > terrible idea is dynamic arrays, and that's the case where the > > compiler _doesn't_ complain. Using == with null and arrays is > > always unclear about the programmer's intent and almost > > certainly wasn't what the programmer intended. If the > > programmer cares about null, they should use is. If they care > > about lengnth, then that's what they should check. Checking > > null with == is just a huge code smell. > > I feel like the array == null version is more explicit about not > allocating memory. However, I'm paranoid about whether that's > going to check the pointer instead, so I mostly use array.length > == 0 instead. I'm not sure what memory allocations you're worried about. Neither "" nor [] allocates memory, but regardless, if you're looking to check whether arr.ptr is null, then that's effectively what you get with arr is null - though IIRC, it still checks length in that case. It's just that the type system guarantees that a null dynamic array has a length of 0. You'd have to do some pretty screwy @system casting to have a null dynamic array with a length other than 0. But you can always do arr.ptr is null Regardless, if you're checking for null, then is does the job, and if what you care about is whether the array is empty, then that's what arr.length == 0 and arr.empty do. arr == null is just risking confusion, because there's no way to know if the programmer meant arr is null or arr.empty Regardless, it's absolutely guaranteed that arr == null is going to avoid checking the value of ptr just like arr == arr2 won't check ptr if length == 0. == only cares that both arrays have the same number of elements and that they're equal with ==. If length is 0, there's no need to check the elements to verify that, and if the lengths don't match, there's no need to check the elements. If you actually used enough screwed up casts to get two dynamic arrays whose ptr values were null, and they had different lengths, you still wouldn't get a crash. The _only_ way to get a segfault from using == with a null dynamic array is if you did enough screwy @system casts to have two dynamic arrays with the same non-zero length, and one of them had a null ptr. It wouldn't even crash if they were both null, because it's going to check the ptrs before comparing the elements. Regardless, in no real program do you have to worry about segfaulting with == and dynamic arrays, and you don't have to worry about == ever allocating. The closest that you'd get to that would be if you compared against a non-null array literal. e.g. arr == [1, 2, 3] and if the compiler is smart enough, not even that should allocate (though I don't remember if it's that smart at the moment). Ultimately, the question of is vs == comes down to clarity of the programmer's intent. - Jonathan M Davis
Re: is ==
On Saturday, 19 May 2018 at 01:48:38 UTC, Jonathan M Davis wrote: Actually, that runtime function has existed since before TDPL came out in 2010. It even shows the implementation of the free function opEquals (which at the time was in object_.d rather than object.d). I'm not even sure that the error message was added before the free function version of opEquals was. Maybe when that error message was first introduced, it avoided a segfault, but if so, it has been a _long_ time since that was the case. Good catch. I overly trusted git blame. The opEquals(Object, Object) function was added in February 2010, while the error message was added in March 2008. Of course, the most notable case where using == with null is a terrible idea is dynamic arrays, and that's the case where the compiler _doesn't_ complain. Using == with null and arrays is always unclear about the programmer's intent and almost certainly wasn't what the programmer intended. If the programmer cares about null, they should use is. If they care about lengnth, then that's what they should check. Checking null with == is just a huge code smell. I feel like the array == null version is more explicit about not allocating memory. However, I'm paranoid about whether that's going to check the pointer instead, so I mostly use array.length == 0 instead.
Re: is ==
On Saturday, May 19, 2018 01:27:59 Neia Neutuladh via Digitalmars-d-learn wrote: > On Friday, 18 May 2018 at 23:53:12 UTC, IntegratedDimensions > > wrote: > > Why does D complain when using == to compare with null? Is > > there really any technical reason? if one just defines == null > > to is null then there should be no problem. It seems like a > > pedantic move by who ever implemented it and I'm hoping there > > is actually a good technical reason for it. > > tldr: this error is outdated. > > In the days of yore, "obj == null" would call > "obj.opEquals(null)". Attempting to call a virtual method on a > null object is a quick path to a segmentation fault. So "obj == > null" would either yield false or crash your program. > > Except it's worse than that; your opEquals method had to > explicitly check for null. So if your class had a custom equality > function, "obj == null" was probably going to segfault no matter > what. > > Because of this common source of errors, in DMD 2.012 (2008), we > got an error only for the case of comparing with a literal null. > (The compiler isn't a mind-reader; it doesn't know whether that > variable will be null when that line of code executes.) > > This still sucked, so in 2015 we got a runtime function to handle > object equality: > https://github.com/dlang/druntime/blob/dff824eda422b1fcdde5f2fe53120fcd717 > 33aaa/src/object.d#L140 > > But we haven't removed the error message. Actually, that runtime function has existed since before TDPL came out in 2010. It even shows the implementation of the free function opEquals (which at the time was in object_.d rather than object.d). I'm not even sure that the error message was added before the free function version of opEquals was. Maybe when that error message was first introduced, it avoided a segfault, but if so, it has been a _long_ time since that was the case. > It *is* faster to call "foo is null" than "foo == null", but I > don't think that's particularly worth a compiler error. The > compiler could just convert it to "is null" automatically in that > case. > > One casualty of the current state of affairs is that no object > may compare equal to null. Honestly, while the compiler probably should just convert obj == null to obj is null, there really still isn't really a good reason to ever use == with null. It's _never_ better than using is, and in some cases, it's worse. Of course, the most notable case where using == with null is a terrible idea is dynamic arrays, and that's the case where the compiler _doesn't_ complain. Using == with null and arrays is always unclear about the programmer's intent and almost certainly wasn't what the programmer intended. If the programmer cares about null, they should use is. If they care about lengnth, then that's what they should check. Checking null with == is just a huge code smell. So, perhaps the compiler is being pedantic, but it's still telling you the right thing. It's just insisting about it in the case where it matters less while not complaining aobut it in the case where it really matters, which is dumb. So IMHO, if anything, adding an error message for the array case would make more sense than getting rid of the error with pointers and references. - Jonathan M Davis
Re: is ==
On Friday, May 18, 2018 23:53:12 IntegratedDimensions via Digitalmars-d- learn wrote: > Why does D complain when using == to compare with null? Is there > really any technical reason? if one just defines == null to is > null then there should be no problem. It seems like a pedantic > move by who ever implemented it and I'm hoping there is actually > a good technical reason for it. Because == is pretty much never what you want to do with null. How much it matters depends on the types involved, but if you really want to check for null, is is definitely the right thing to use. In the case of pointers and references, is checks that they're pointing to the same thing. So, foo is null directly checks whether the reference or pointer is null. On the other hand, if you use ==, it's calling some form of opEquals. For pointers, that should generate identical code, but for class references, it means calling the free function opEquals. That function will check whether the references are null before calling opEquals on either of the class objects, but it does add unnecessary overhead (which, as I understand it, the compiler is unfortunately not currently able to optimize away) and provides no benefit over checking with is. Now, where is vs == _really_ matters (but unfortunately, the compiler does not complain about) is with dynamic arrays. If you do arr is null then the compiler will check whether the array's ptr is null. So, something like "" is null would be false. However, if you use ==, then it compares the length of the array and then only compares the ptrs if the length is non-zero. So, "" == null is true. So, with dynamic arrays, using == with null is a huge code smell. It _may_ be exactly what the programmer intends, but the odds are pretty high that they just don't properly understand the difference between is and ==, and they meant to be checking whether the array was actually null but just ended up checking whether its length was zero (which won't matter for some code but will cause subtle bugs in any code that treats null as special - e.g. if that is used to indicate that the array had not been given a value). Now, because of how == treats null like empty, it _is_ a bit risky to try and treat null as special with arrays, but anyone wanting to be clear in their code should either be checking null with is (in which case, they clearly care about null and not empty), or if they care about length == 0, they should either be calling empty on the array or explicitly checking the array's length, since that's what they care about. Much as having == work with null arrays avoids issues with segfaults due to an array be unitialized as well as avoids needing to give memory to an array just to have it be empty, you pretty much never actually care whether an array == null. You either care that its ptr is null (in which case, is checks that), or you care about whether its length is 0 (in which case empty or directly checking length checks that). arr == null is just unclear and likely buggy. So really, there are _zero_ advantages to comparing null with ==. Using == with null risks adding extra overhead, and it often makes the code less clear. On the other hand, using is makes it crystal clear what you mean and then does exactly what you mean - check whether the variable is actually null. So, maybe the compiler is being a bit pedantic by insisting that you use is rather than ==, but you really should be using is and not == when checking for null. - Jonathan M Davis
Re: is ==
On Friday, 18 May 2018 at 23:53:12 UTC, IntegratedDimensions wrote: Why does D complain when using == to compare with null? Is there really any technical reason? if one just defines == null to is null then there should be no problem. It seems like a pedantic move by who ever implemented it and I'm hoping there is actually a good technical reason for it. tldr: this error is outdated. In the days of yore, "obj == null" would call "obj.opEquals(null)". Attempting to call a virtual method on a null object is a quick path to a segmentation fault. So "obj == null" would either yield false or crash your program. Except it's worse than that; your opEquals method had to explicitly check for null. So if your class had a custom equality function, "obj == null" was probably going to segfault no matter what. Because of this common source of errors, in DMD 2.012 (2008), we got an error only for the case of comparing with a literal null. (The compiler isn't a mind-reader; it doesn't know whether that variable will be null when that line of code executes.) This still sucked, so in 2015 we got a runtime function to handle object equality: https://github.com/dlang/druntime/blob/dff824eda422b1fcdde5f2fe53120fcd71733aaa/src/object.d#L140 But we haven't removed the error message. It *is* faster to call "foo is null" than "foo == null", but I don't think that's particularly worth a compiler error. The compiler could just convert it to "is null" automatically in that case. One casualty of the current state of affairs is that no object may compare equal to null.
Re: is ==
On Friday, 18 May 2018 at 23:58:18 UTC, Uknown wrote: On Friday, 18 May 2018 at 23:53:12 UTC, IntegratedDimensions wrote: Why does D complain when using == to compare with null? Is there really any technical reason? if one just defines == null to is null then there should be no problem. It seems like a pedantic move by who ever implemented it and I'm hoping there is actually a good technical reason for it. D only complains of this when you use ref types (classes or AAs). For e.g: --- test.d void main() { int * p; assert (p == null && p is null); class C { int x; } C c; assert (c is null); assert (c == null); //error, c is a reference, so there is confusion between opEquals and null check } --- or pointers.
Re: is ==
On Friday, 18 May 2018 at 23:53:12 UTC, IntegratedDimensions wrote: Why does D complain when using == to compare with null? Is there really any technical reason? if one just defines == null to is null then there should be no problem. It seems like a pedantic move by who ever implemented it and I'm hoping there is actually a good technical reason for it. D only complains of this when you use ref types (classes or AAs). For e.g: --- test.d void main() { int * p; assert (p == null && p is null); class C { int x; } C c; assert (c is null); assert (c == null); //error, c is a reference, so there is confusion between opEquals and null check } ---
is ==
Why does D complain when using == to compare with null? Is there really any technical reason? if one just defines == null to is null then there should be no problem. It seems like a pedantic move by who ever implemented it and I'm hoping there is actually a good technical reason for it.
Re: Temporary file creation for unittests
On Friday, 18 May 2018 at 15:30:05 UTC, Uknown wrote: On Friday, 18 May 2018 at 15:16:52 UTC, Russel Winder wrote: Hi, What's the current official position on how to create temporary files for use during a unittest. I found https://github.com/dlang/phobos/pull/5788 but it seems to be languishing in the "we have discussed all the issues that no-one will ever have a problem with" phase. What to do between now and when there is an LDC release that has the result of the merge? You could use libc's tmpfile with std.stdio.File until a D alternative pops up. http://en.cppreference.com/w/c/io/tmpfile I've had no idea C++'s got this in the standard library lol a while ago I ended up doing this (on Windows): /// Creates a uniquely named, zero-byte temporary file on disk and returns the full path of that file. /// Returns: the full path of the temp file. string tempFilename() { import core.sys.windows.windows : GetTempFileNameW, MAX_PATH; import std.file : tempDir; import core.stdc.wchar_ : wcslen; import std.windows.syserror : wenforce; import std.conv : text, wtext; wchar[] path = new wchar[MAX_PATH+1]; string dir = tempDir; wenforce(GetTempFileNameW(dir.wtext.ptr, // temp path ("tmp"w).ptr, // dir prefix 0, // id generated internally path.ptr // path buffer ), "GetTempFileName()"); return path[0 .. wcslen(path.ptr)].text; } It's windows-only and call GetTempFileNameW actually so just a function wrapper to work with D. There's a way to MAX_PATH but I didn't care to implement at time...
Re: Temporary file creation for unittests
On Friday, 18 May 2018 at 15:16:52 UTC, Russel Winder wrote: Hi, What's the current official position on how to create temporary files for use during a unittest. I found https://github.com/dlang/phobos/pull/5788 but it seems to be languishing in the "we have discussed all the issues that no-one will ever have a problem with" phase. What to do between now and when there is an LDC release that has the result of the merge? You could use libc's tmpfile with std.stdio.File until a D alternative pops up. http://en.cppreference.com/w/c/io/tmpfile
Temporary file creation for unittests
Hi, What's the current official position on how to create temporary files for use during a unittest. I found https://github.com/dlang/phobos/pull/5788 but it seems to be languishing in the "we have discussed all the issues that no-one will ever have a problem with" phase. What to do between now and when there is an LDC release that has the result of the merge? -- Russel. == Dr Russel Winder t: +44 20 7585 2200 41 Buckmaster Roadm: +44 7770 465 077 London SW11 1EN, UK w: www.russel.org.uk signature.asc Description: This is a digitally signed message part
Re: C API / const char *text / std.string.toStringz pointer is always NULL on C side
On Friday, 18 May 2018 at 14:06:11 UTC, Robert M. Münch wrote: So, having a wrong return-type here, resulted in the const char *text parameter always being NULL. Not sure I understand the relation but looks strange to me... at least not very obvious. A value struct return is actually done via a hidden pointer parameter (so the function can construct it in-place for the caller, a standard optimization), so it just shifted all the other arguments to the side, causing one of those 0's to be interpreted as the string.
Re: C API / const char *text / std.string.toStringz pointer is always NULL on C side
On 2018-05-16 17:46:59 +, Steven Schveighoffer said: Well, for C see above on the D side: extern(C) { result myfunc(double x, double y, const char *text, stuff *myStuff, bool measureOnly); } Shouldn't the result be a pointer? Indeed. And you know what? That was causing the problem. So, having a wrong return-type here, resulted in the const char *text parameter always being NULL. Not sure I understand the relation but looks strange to me... at least not very obvious. -- Robert M. Münch http://www.saphirion.com smarter | better | faster
Re: Template instantiation fails on Linux, succeeds on Windows
On 5/17/18 7:33 PM, Bastiaan Veelo wrote: On Thursday, 17 May 2018 at 23:18:32 UTC, Basile B. wrote: On Thursday, 17 May 2018 at 22:07:46 UTC, Bastiaan Veelo wrote: Hi! The code in [1] compiles and runs flawlessly on Windows, but not on Linux (neither run.dlang nor Travis docker image). Any idea what can be done? Hello. Yes, add `import core.stdc.stdarg;` in your module and it works. I don't know why it's not required on windows, this is strange. Great! Thanks a lot, Basile! Seems there is room for improvement somewhere, a better error message at the least. Interestingly, the error was better before: https://run.dlang.io/is/BgvH4w Tested on all compilers, up to 2.072.1, it results in: onlineapp.d(1): Error: '__va_argsave_t' is not defined, perhaps you need to import core.vararg; ? onlineapp.d(1): Error: function onlineapp.foo must import core.vararg to use variadic functions In 2.072.2, it starts saying: Error: undefined identifier '__va_list_tag' The previous error was much better, but this to me is a huge code smell. Why do we have to import certain modules to use actual language features? Just to *define* a function, but not do anything inside it? I'd understand if this was a linker error, but surely the compiler can know to auto-import something, or at least spit out the proper extern(C) declarations? Note that your code works if I import core.vararg outside the function, you don't need core.stdc.stdarg. The import cannot be *inside* the function. -Steve
Re: Splitting up large dirty file
On Thursday, 17 May 2018 at 20:08:09 UTC, Dennis wrote: ``` auto inputStream = (args.length < 2 || args[1] == "-") ? stdin : args[1].File; auto outputFile = new File("output.txt"); foreach (line; inputStream.byLine(KeepTerminator.yes)) outputFile.write(line); ``` Do it old school? --- int line; auto outputFile = File("output.txt", "wb"); foreach (chunk; inputStream.byChunk(4<<10)) { auto rem=chunk; while(rem!=null) { auto i=rem.countUntil(10); auto len=i+1; if(i<0)len=rem.length; else line++; outputFile.rawWrite(rem[0..len]); rem=rem[len..$]; } } ---