June 29, 2004
>>>> 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.
>
>Thus why just about no-one ever does this (in C). They all return a pointer to a struct.

Because copying a struct costs much more than just copying a pointer to it. In C++ you have references for things like this, which can't be NULL.

>>> 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.
>
>Fine and dandy EXCEPT we *need* to differentiate between empty and non-existant strings.
>
>> D arrays simply do not work that way.
>
>In that case we need an array specialisation for strings, so I'll have to write my own. This defeats the purpose of char[] in the first place, which was, to be a better more consistent  string handling method than in possible in c/c++.
>

Could you please make some real world examples, where you need empty strings and null-strings?

-- Matthias Becker


June 29, 2004
>>> Yeah, it's called std::string, and it's more or less the default.
>>
>>And it's crap. IMNSHO.
>
>You'll get no arguments from me there. D got it right in not having a string class. I didn't think that at first, but I've come round to the D way of thinking. The problem with a string class is that you can't add new member functions to it. (Oh, you may be able to subclass String, if it's not final. Oh wait - it /is/ final in Java). With char[] arrays, you CAN add new functions.
>

Why do you need to add member-functions to a string class, but you don't on
char-arrays? Why are global functions OK for char-arrays, but aren't for a
string class?
This is some kind of strange. Just because another notation? Does taht realy
matters? There are languages where you can wirte:

object.function()
and
function(objekt)

and it measn the same.

I don't get your point.

>>> Don't compare arrays to null.  Don't try to differentiate between empty and nonexistent.
>>
>>Fine and dandy EXCEPT we *need* to differentiate between empty and non-existant strings.
>
>Why? Do we also need a way to differentiate between empty and non-existent ints?
>
>In D, there is no such thing as a non-existent int; there is no such thing as a non-existent struct; and there is no such thing as a non-existent string.

Something like that would be cool, just like option in SML. I think I have to write something like this.

-- Matthias Becker


June 29, 2004
>> In C++, there is no such thing as an uninitialized vector. Why on Earth would you want them in D?
>For the same reason you use null in other situations with reference types. I want accessing an uninitialised member array to give an error. I want to be able to use a null argument to a function to trigger special or default behaviour (optional arguments in any position).

Nope, wrong.

If you use reference-types that are allowed to be NULL (in C++ references aren't, e.g. in nice there are references, that aren't, too, ...) you want to show that there possibly is no object. At least in languages that allow you to use other kinds of references (e.g. C++ or nixe as mentiond above).

In languages that don't have references that can't be null, you just can't express yourself in the code.



In C++ I never had the wish to pass a container/collection as a pointer. I
allways pass them as C++-reference. So I'm sure there allways is a collection
and I don't have to check for this.
If there are no values to pass in, I just pass an empty collection.


Could you please make some example where it makes sense not to pass a collection instead of passing an empty collection?

-- Matthias Becker


June 29, 2004
In article <opsab6o5rl5a2sq9@digitalmars.com>, Regan Heath says...
>
>Fine and dandy EXCEPT we *need* to differentiate between empty and non-existant strings.

Why?  It seems to me that this behavior would also require arrays to be initialized with new rather than resizing from zero using the .length parameter. And this would result in a ton of extra coding--either in clauses that errored on null arrays or initialization code to handle both cases.  No thanks.  If this happened I'd stil using built-in arrays and write a class for the purpose.

Sean


June 29, 2004
In article <cbrhd9$1a0o$1@digitaldaemon.com>, Sam McCall says...
>
>> This might be very handy.  If so, I wouldn't mind seeing rbegin and rend parameters as well though.
>Huh? They're pointers... wouldn't rbegin == end and rend == begin? I think I missed the point...

Actually, rbegin == end-1 and rend == begin-1.

>> Plus, it raises the question of what they return for associative arrays.
>The concept doesn't apply to associative arrays afaics, so they wouldn't exist.

It does apply to associative arrays IMO.  I iterate through the contents of such containers quite regularly in C++.  I've done something similar with an iterator wrapper for associative arrays in D, but it would be nice to have this built-in if we move towards the iterator methodology.

Sean


June 29, 2004
Norbert Nemec <Norbert.Nemec@gmx.de> wrote in news:cbrogr$1jp7$1@digitaldaemon.com:

> Arcane Jill wrote:
> 
[snip]
> 
>> But anyway, Farmer tells me I can write cast(elementtype*)a+n, so I'm
>> happy.
> 
> Well - that's a workaround but not a clean solution.
> 

In Jill's example, a *C* function expects a pointer to anything, not a D- array. So, I think, it makes perfect sense to convert the D array to the pointer type first, and than do pointer arithmetic as in C. (If you need the behaviour of a pointer, use one.)


Farmer.
June 29, 2004
Andy Friesen <andy@ikagames.com> wrote in news:cbpsi6$1u7d$1@digitaldaemon.com:

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

And probably that is one reason why programmers don't use std::vector.

<rant>
If I wanted to use sth. like std::vector, I'd simply use them in D. But if I
want to get to the *bare metal*, I want the *bare metal*. No less. I don't
want sth. that is similar to std::vector (just better tuned for performance),
tightly integrated (or coupled, in book) with the language, with some odd
syntax and superfluous but still incomplete properties like array.sort. Even
if that means that I have to code a bubble sort, all the time myself ;-)
<end of rant>


Farmer.
June 29, 2004
Arcane Jill <Arcane_member@pathlink.com> wrote in news:cbr53s$op8$1@digitaldaemon.com:

[snip]
> Why? Do we also need a way to differentiate between empty and non-existent ints?
Yes, we do. A slightly *naive*  but definitely opinionated soul already suggested exactly this. Unfortunately, this is not implementable without unacceptable performance loss. So we cannot have this.

[snip]

> Maybe the real solution would be to make it a compile error to assign an array with null, or to compare it with null. This would then force people to say what they mean, and all such problems would go away.

I agree, that would help to avoid some confusion. Unfortunately, people would be forced to either say 'I mean empty' or to shut up completely and use sth. completely different.


Farmer.

June 29, 2004
Sean Kelly <sean@f4.ca> wrote in news:cbs4ju$26aj$1@digitaldaemon.com:

> In article <opsab6o5rl5a2sq9@digitalmars.com>, Regan Heath says...
>>
>>Fine and dandy EXCEPT we *need* to differentiate between empty and non-existant strings.
> 
> Why?  It seems to me that this behavior would also require arrays to be initialized with new rather than resizing from zero using the .length parameter. And this would result in a ton of extra coding--either in clauses that errored on null arrays or initialization code to handle both cases. [...]

The .length parameter would still work with null-arrays (as they currently do). But why would you want to initialize an array to null/empty and then resize it, instead of 'newing' it with the correct size in first place? My CPU gets hot enough, no need for extra heat-up cycles :-)

Extra coding is not required if you don't need null-arrays: if some user passes a null-array, the user gets a nice access violation/array bounds exception and will quickly learn to not pass null-arrays to such functions. A quick check in the DbC section of your function would do the job, too. (But I suppose, the user might not adapt that fast that way :-)

If your function should deal with both null-arrays and empty-arrays, no extra code is required, since the .length property can be accessed for both null- arrays and emtpy-arrays.


>[...] No thanks.  If this happened I'd stil using built-in arrays
> and write a class for the purpose.

I came to the same conclusion, wrapping a build-in array in a class or struct to adapt its behaviour to the specific needs is one (if not the) way to go.


Farmer.
June 29, 2004
In article <Xns9517F3F654C29itsFarmer@63.105.9.61>, Farmer says...
>
>The .length parameter would still work with null-arrays (as they currently do). But why would you want to initialize an array to null/empty and then resize it, instead of 'newing' it with the correct size in first place?

Consider the following:

char[] str = new char[100];
str.length = 0; // A
str.length = 5; // B
str = new char[10]; // C

In A, AFAIK it's legal for the compiler to retain the memory and merely change the length parameter for the string.  B then just changes the length parameter again, and no reallocation is performed.  C forces a reallocation even if the array already has the (hidden) capacity in place.  Lacking allocators, this is a feature I consider rather nice in D.

>Extra coding is not required if you don't need null-arrays: if some user passes a null-array, the user gets a nice access violation/array bounds exception and will quickly learn to not pass null-arrays to such functions. A quick check in the DbC section of your function would do the job, too. (But I suppose, the user might not adapt that fast that way :-)

I originally thought D worked the way you describe and added DBC clauses to all my functions to check for null array parameters.  After some testing I realized I'd been mistaken and happily removed most of these clauses.  The result IMO was tighter, cleaner code that was easier to understand.  I suppose it's really a matter of opinion.  I like that arrays work the same as the other primitive types.

>If your function should deal with both null-arrays and empty-arrays, no extra code is required, since the .length property can be accessed for both null- arrays and emtpy-arrays.

Could it?  I suppose so, but the concept seems a tad odd.  I kind of expect none of the parameters (besides sizeof, perhaps) to work for dynamic types that have not been initialized.  Though perhaps that's the C way of thinking.


Sean