June 28, 2004
In article <cbpkes$1ip0$1@digitaldaemon.com>, Arcane Jill says...
>
>Indeed, I think it has always worked. It was just me misremembering the problem. I'll start again. What I MEANT was...
>
>Given that a is an array of length n, the expression &a[n] gives an array bounds exception. And I don't believe it should. Taking the address of the first byte beyond the end of an array can be a very useful thing to do.

Yes it is.  But I think it's the syntax that's the problem in this case.  IIRC using the subscript operator (ie. [n]) dereferences the element.  So what you're doing when you call &a[n] is calculating the address of the element at position n.  Since no such element exists, the call fails.  In C the correct thing to do would be to use (a+n) instead.

Just to make sure I was right, I dug this quote out of the C++ standard (5.2.1):
"The expression E1[E2] is identical (by definition) to *((E1)+(E2))."

>The fact of not being able to take &a[a.length] creates an akwardness that we have to code around.

A possibility would be to have the compiler treat &a[n] as a special case... since the address-of operator is present, it could treat this expression as equivalent to: "a+n" rather than "&*(a+n)"


Sean


June 28, 2004
Arcane Jill wrote:

> The fact of not being able to take &a[a.length] creates an akwardness that we
> have to code around. The above example would have to be encased in an if test in
> order not to assert - and you might think: So what? This is no big deal. But
> having to make that explicit test time and time again can start to get annoying.
> 
> It should not, in my opinion, be an error to evaluate &a[a.length];

Something which just occurred to me that would resolve this issue would be to add two properties to array types: begin and end.  These properties would be pointer types which point to the beginning and end of the array's contents.  (exactly like C++ iterators)

    T[] buffer = ...;
    // buffer.length makes more sense than end-begin in this case.
    // Bear with me: it's an example :)
    fread(buffer.begin, T.sizeof, buffer.end - buffer.begin, fileHandle);

 -- andy
June 28, 2004
Regan Heath wrote:

> I see what you're saying... the internal data pointer for the array can be null or non-null however, this is the difference between an un-initialized (or null) array and an empty one.
> 
> I dont care how we do it, I just know we need to be able to tell the difference for 'strings'. Perhaps this applies to all arrays. Perhaps strings need to be a specialized form of array...

You say that as though it is self-evident that strings must absolutely, unequivocably be, at all costs, reference types.  Why?

C++ containers cannot represent null either.  D will (and does) get along just fine if its array type works the same way.

>> This goes back to D performing implicit pointer conversion.  Comparing arrays with null is not a good idea.
> 
> Perhaps not, but, there is currently no other way to tell the difference between an empty string and a null string. This is very important.

A 'null array' is a completely arbitrary concept that has been extrapolated from undefined behaviour. :)

(check the documentation concerning arrays.  Nowhere does the concept of a null array appear.  The only place the keyword 'null' even occurs is a blip which says that arrays are initialized with their data pointer set to null)

>> I'm still forming an opinion on whether this is the right thing to do or not.  If comparing arrays with pointers was illegal, this issue would never arise.
> 
> True, but then you wouldn't be able to tell null strings from empty ones.

Because there is no such thing.  As far as D is concerned, all arrays exist.  Some contain elements, others don't.  Whether its data pointer is null or not does not set it apart from any other empty array.

 -- andy
June 28, 2004
In article <cbprfd$1sq9$1@digitaldaemon.com>, Andy Friesen says...
>
>Something which just occurred to me that would resolve this issue would be to add two properties to array types: begin and end.  These properties would be pointer types which point to the beginning and end of the array's contents.  (exactly like C++ iterators)

This might be very handy.  If so, I wouldn't mind seeing rbegin and rend parameters as well though.  Plus, it raises the question of what they return for associative arrays.

Sean


June 28, 2004
Arcane Jill <Arcane_member@pathlink.com> wrote in news:cbpkes$1ip0$1@digitaldaemon.com:


> Given that a is an array of length n, the expression &a[n] gives an array bounds exception. And I don't believe it should. Taking the address of the first byte beyond the end of an array can be a very useful thing to do.

The expression  cast(elementtype*)a+n , does that.

E.g. to get rid of annoying bounds-checking you could write.
    // given ubyte[] a;
    fread(cast(ubyte*)a+0, ubyte.size, a.length, fp);


Farmer.
June 28, 2004
On Mon, 28 Jun 2004 12:50:08 -0700, Andy Friesen <andy@ikagames.com> wrote:
> Regan Heath wrote:
>
>> I see what you're saying... the internal data pointer for the array can be null or non-null however, this is the difference between an un-initialized (or null) array and an empty one.
>>
>> I dont care how we do it, I just know we need to be able to tell the difference for 'strings'. Perhaps this applies to all arrays. Perhaps strings need to be a specialized form of array...
>
> You say that as though it is self-evident that strings must absolutely, unequivocably be, at all costs, reference types.  Why?

If it's not a reference type, then how can you signal non-existance (null)?

> C++ containers cannot represent null either.  D will (and does) get along just fine if its array type works the same way.

I have not used C++ containers. I program in C for a living, and C++ for a hobby. Is there a C++ container for strings that cannot tell the difference between non-existant and empty?

>>> This goes back to D performing implicit pointer conversion.  Comparing arrays with null is not a good idea.
>>
>> Perhaps not, but, there is currently no other way to tell the difference between an empty string and a null string. This is very important.
>
> A 'null array' is a completely arbitrary concept that has been extrapolated from undefined behaviour. :)

It may be undefined, but I believe it is required.

> (check the documentation concerning arrays.  Nowhere does the concept of a null array appear.  The only place the keyword 'null' even occurs is a blip which says that arrays are initialized with their data pointer set to null)

So it's undefined, lets define it.

>>> I'm still forming an opinion on whether this is the right thing to do or not.  If comparing arrays with pointers was illegal, this issue would never arise.
>>
>> True, but then you wouldn't be able to tell null strings from empty ones.
>
> Because there is no such thing.

Yes there is. The concept exists, in C and in our examples.

> As far as D is concerned, all arrays exist.  Some contain elements, others don't.  Whether its data pointer is null or not does not set it apart from any other empty array.

Yes it does. This behaviour exists, it's just currently undefined (as you say) and inconsistent (as Farmer has pointed out).

The soln IMO is either to make the current behaviour official and consistent, or to change the behaviour, make that official and provide another way to tell null apart from an empty string.

Regan.

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
June 28, 2004
On Mon, 28 Jun 2004 17:27:56 +0000 (UTC), Arcane Jill <Arcane_member@pathlink.com> wrote:

> In article <opr99w0st25a2sq9@digitalmars.com>, Regan Heath says...
>>> (1) given that a is an array of length n, the expression a[n..n] gives
>>> an array
>>> bounds exception,
>
>> This (now?) works.
>
> Indeed, I think it has always worked. It was just me misremembering the problem.
> I'll start again. What I MEANT was...
>
> Given that a is an array of length n, the expression &a[n] gives an array bounds
> exception. And I don't believe it should. Taking the address of the first byte
> beyond the end of an array can be a very useful thing to do.
>
> In particular, if a is an empty array, then &a[0] asserts, which means that code
> like this:
>
> #    // given ubyte[] a;
> #    fread(&a[0], ubyte.size, a.length, fp);
>
> intended to fill an array from a FILE*-type stream, will fall over if a is
> empty. And there's no reason why it should - fread is quite happy to be passed a
> length of zero. Same goes for functions like memset() and so on.
>
> The fact of not being able to take &a[a.length] creates an akwardness that we
> have to code around. The above example would have to be encased in an if test in
> order not to assert - and you might think: So what? This is no big deal. But
> having to make that explicit test time and time again can start to get annoying.
>
> It should not, in my opinion, be an error to evaluate &a[a.length];

Interestingly..

void main()
{
	char[] p,s;
	s.length = 10;
	printf("%08x\n",&s[0]);
	printf("%08x\n",&p[0]);
}

D:\D\src\build\temp>dmd arr.d
d:\D\dmd\bin\..\..\dm\bin\link.exe arr,,,user32+kernel32/noi;

D:\D\src\build\temp>arr
007d0fd0
Error: ArrayBoundsError arr.d(6)

So it seems Sean is indeed correct about what p[0] is doing (de-referencing the element)

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
June 28, 2004
Regan Heath wrote:
> On Mon, 28 Jun 2004 12:50:08 -0700, Andy Friesen <andy@ikagames.com> wrote:
>> You say that as though it is self-evident that strings must absolutely, unequivocably be, at all costs, reference types.  Why?
> If it's not a reference type, then how can you signal non-existance (null)?

You don't.

> I have not used C++ containers. I program in C for a living, and C++ for a hobby. Is there a C++ container for strings that cannot tell the difference between non-existant and empty?

Yeah, it's called std::string, and it's more or less the default.

>> A 'null array' is a completely arbitrary concept that has been extrapolated from undefined behaviour. :)
> It may be undefined, but I believe it is required.

Why?  C++ gets along without them just fine, and every C derivant I know of gets along fine without allowing primitive type returns to signify nonexistence.

Functions which returns structs cannot return null either.

> The soln IMO is either to make the current behaviour official and consistent, or to change the behaviour, make that official and provide another way to tell null apart from an empty string.

Farmer's test reports pretty consistent results if you suppose that comparing arrays to null is ill-formed:

    empty1.length == 0    is true
    empty1 == ""          is true
    empty2.length == 0    is true
    empty2 == ""          is true
    empty3.length == 0    is true
    empty3 == ""          is true

Don't compare arrays to null.  Don't try to differentiate between empty and nonexistent.  D arrays simply do not work that way.

 -- andy
June 29, 2004
On Mon, 28 Jun 2004 16:33:25 -0700, Andy Friesen wrote:

> Regan Heath wrote:
>> On Mon, 28 Jun 2004 12:50:08 -0700, Andy Friesen <andy@ikagames.com> wrote:
>>> You say that as though it is self-evident that strings must absolutely, unequivocably be, at all costs, reference types.  Why?
>> If it's not a reference type, then how can you signal non-existance (null)?
> 
> You don't.
> 
>> I have not used C++ containers. I program in C for a living, and C++ for a hobby. Is there a C++ container for strings that cannot tell the difference between non-existant and empty?
> 
> Yeah, it's called std::string, and it's more or less the default.
> 
>>> A 'null array' is a completely arbitrary concept that has been extrapolated from undefined behaviour. :)
>> It may be undefined, but I believe it is required.
> 
> Why?  C++ gets along without them just fine, and every C derivant I know of gets along fine without allowing primitive type returns to signify nonexistence.
> 
> Functions which returns structs cannot return null either.
> 
>> The soln IMO is either to make the current behaviour official and consistent, or to change the behaviour, make that official and provide another way to tell null apart from an empty string.
> 
> Farmer's test reports pretty consistent results if you suppose that comparing arrays to null is ill-formed:
> 
>      empty1.length == 0    is true
>      empty1 == ""          is true
>      empty2.length == 0    is true
>      empty2 == ""          is true
>      empty3.length == 0    is true
>      empty3 == ""          is true
> 
> Don't compare arrays to null.  Don't try to differentiate between empty and nonexistent.  D arrays simply do not work that way.
> 
>   -- andy

Agreed, D doesn't seem to work that way, but isn't that the issue. Some people would like to distinguish between an uninitialized array, and an initialized but empty array.

-- 
Derek
Melbourne, Australia
29/Jun/04 10:44:05 AM
June 29, 2004
> Don't compare arrays to null.  Don't try to differentiate between empty and nonexistent.  D arrays simply do not work that way.

I must say, I kind of like that. I don't have to write a read/write property where the write property has an in/out contract to guard against internal/external code setting an array member field to null -- goodbye bloat!