Re: is ==

2018-05-18 Thread Jonathan M Davis via Digitalmars-d-learn
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 ==

2018-05-18 Thread Neia Neutuladh via Digitalmars-d-learn

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

2018-05-18 Thread Jonathan M Davis via Digitalmars-d-learn
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 ==

2018-05-18 Thread Jonathan M Davis via Digitalmars-d-learn
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 ==

2018-05-18 Thread Neia Neutuladh via Digitalmars-d-learn
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 ==

2018-05-18 Thread IntegratedDimensions via Digitalmars-d-learn

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

2018-05-18 Thread Uknown via Digitalmars-d-learn
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 ==

2018-05-18 Thread IntegratedDimensions via Digitalmars-d-learn
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

2018-05-18 Thread Dr.No via Digitalmars-d-learn

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

2018-05-18 Thread Uknown via Digitalmars-d-learn

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

2018-05-18 Thread Russel Winder via Digitalmars-d-learn
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

2018-05-18 Thread Adam D. Ruppe via Digitalmars-d-learn

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

2018-05-18 Thread Robert M. Münch via Digitalmars-d-learn

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

2018-05-18 Thread Steven Schveighoffer via Digitalmars-d-learn

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

2018-05-18 Thread Kagamin via Digitalmars-d-learn

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..$];
  }
}
---