On Fri, 01 Apr 2011 11:52:47 -0400, Regan Heath <re...@netmail.co.nz>
wrote:
On Fri, 01 Apr 2011 13:38:45 +0100, Steven Schveighoffer
<schvei...@yahoo.com> wrote:
On Fri, 01 Apr 2011 06:38:56 -0400, Regan Heath <re...@netmail.co.nz>
wrote:
On Mon, 28 Mar 2011 17:54:29 +0100, bearophile
<bearophileh...@lycps.com> wrote:
Steven Schveighoffer:
So essentially, you are getting the same thing, but using [] is
slower.
It seems I was right then, thank you and Kagamin for the answers.
This may be slightly OT but I just wanted to raise the point that
conceptually it's nice to be able to express (exists but is empty) and
(does not exist). Pointers/references have null as a (does not exist)
"value" and this is incredibly useful. Try doing the same thing with
'int' .. it requires you either use int* or pass an additional boolean
to indicate existence.. yuck.
I'd suggest if someone types '[]' they mean (exists but is empty) and
if they type 'null' they mean (does not exist) and they may be relying
on the .ptr value to differentiate these cases, which is useful. If
you're not interested in the difference, and you need performance, you
simply use 'null'. Everybody is happy. :)
The distinction is useful if you have something to reference (e.g. an
empty slice that points at the end of a pre-existing non-empty array).
But [] is a new array, no point in allocating memory just so the
pointer can be non-null. Can you come up with a use case to show why
you'd want such a thing?
Ok. Recently I wrote (in C) a function proxy interface. I had to
execute a set of functions from one thread, and wanted to 'call' them
from potentially many. So, I set up the thread, added events, and a
queue, etc and I wrote a proxy function for 'calling' them from the many
threads which looks like...
void proxy(int func, ...) {}
So, it accepts a variable list of args, places them in a structure,
places that in the queue, and waits on an event for the proxy thread to
execute the command and return the result. Lets say the function I am
executing is a database lookup, lets say I have a database field which
is a string, lets say it can be NULL (database definition allows
NULLS). Now, lets say I want to do these lookups:
1. lookup all objects where the field is NULL
2. lookup all objects where the field is "reganwashere"
3. lookup all objects where the field is "" (empty/non-null)
#1 and #2 are simple enough. I call proxy like..
proxy(LOOKUP, NULL);
proxy(LOOKUP, "reganwashere");
and in the actual lookup function, invoked by proxy, I call:
pFieldValue = va_arg(pArgs, char*);
and I get NULL, and "reganwashere".
In C, case #2 would also be easy, I would call proxy(LOOKUP, "") and in
the actual lookup function pFieldValue would be "" (not NULL).
But, in D it seems I cannot do this. In D I would have to pass an
additional boolean parameter, or add another level of indirection i.e.
pass a string[]*. The same problem exists in C if I want to pass an
'int' or any primitive type, I have to pass it as int*, use a boolean,
or invent a 'special' value which means essentially NULL/not-set/ignored.
assert("" !is null); // works on D. Try it.
Your plan would mean that [] is a memory allocation. I'd rather not
have the runtime do the lower performing thing unless there is a good
reason.
I'm not too bothered what syntax gets used, provided it was something
that you don't accidently use when you do not want it, and wasn't too
horrible to use as I don't see this as being a very uncommon occurance
(which would warrant/allow ugliness of syntax). "[]" seems logical, as
does "new T[]", both are not "null" so the programmer was obviously
trying to do something other than pass null.
It's one thing to want an array with a non-null pointer, but it's another
thing entirely to want an array with a non-null pointer which points to a
valid heap address.
In my opinion, [] means empty array. I don't care what the pointer is, as
long as the array is empty. The implementation can put whatever value it
wants for the pointer. If it wants to put null, that is fine. null means
I want a null pointer.
If I had it my way, all array literals would be immutable, and the
pointers would point to ROM (even empty ones). We should not be
constructing array literals at runtime. But my opinion is still that you
should not count on the pointer being anything because it's not specified
what it is.
As an alternative, you could use (cast(T *)null)[1..1] if you really
needed it (this also would be higher performing, BTW since the runtime
array literal function would not be called).
That seems to work, but it's hideous syntax for something that is not
that uncommon IMO.
My opinion is that it is uncommon, but it can be abstracted:
template emptyArray(T)
{
enum emptyArray = (cast(T*)0)[1..1];
}
rename as desired.
To remind myself what D does, and try and find another way to achive the
same thing I wrote a test case:
--------------------
import std.stdio;
char[] foo(int state)
{
switch(state)
{
default:
case 0:
return null;
case 1:
return [];
case 2:
return new char[0];
case 3:
return (cast(char *)null)[1..1];
case 4:
return cast(char[])"".dup;
case 5:
return cast(char[])""[0..0];
}
}
int main(string[] args)
{
foreach(int i; 0..6)
{
char[] arr = foo(i);
writefln("foo%d 0x%08x,%d",
i,
arr.ptr,
arr.length);
}
return 0;
}
Which outputs:
foo0 0x00000000,0
foo1 0x00000000,0
foo2 0x00000000,0
foo3 0x00000001,0 <- your suggestion
foo4 0x00000000,0
foo5 0x00000000,0
So, your suggestion appear to be the only way to get an empty array in D.
R
This code seems to disagree with your results for case 5 (dmd 2.052):
auto x = cast(char[])""[0..0];
assert(x.ptr != null); // no failure
-Steve