July 24, 2005
Regan Heath wrote:

>> What do you mean by can't be null?
> 
> char[] p = null;
> if (p.length == 0) { //does not crash, p itself is never 'null' }

Okay... I obviously don't get D strings because this seems wildly counter-intuitive to me. Sure if p CANNOT be null, the line

char[] p = null; // Surely this means: set p to null

should fail to compile or throw an exception or something?

If D strings truly couldn't be null I would expect something like:

// Declare p
// p is initialized to empty (not null - it can never be null)
char[] p;

// Test for empty
// A test for null makes no sense - p can never be null
if (!p) {}

What am I missing?

James McComb
July 24, 2005
On Mon, 25 Jul 2005 08:55:09 +1000, James McComb <ned@jamesmccomb.id.au> wrote:
> Regan Heath wrote:
>
>>> What do you mean by can't be null?
>>  char[] p = null;
>> if (p.length == 0) { //does not crash, p itself is never 'null' }
>
> Okay... I obviously don't get D strings because this seems wildly counter-intuitive to me. Sure if p CANNOT be null, the line
>
> char[] p = null; // Surely this means: set p to null
>
> should fail to compile or throw an exception or something?

I understand where you're going with this, the important fact here is that though an array reference itself cannot be null it still behaves like any other reference set to null(*). eg.

char[] p = null;
if (p is null) { //true }

(*) with the exception that you can de-reference an array that has been set to null, eg.

char[] p = null;
if (p.length == 0) { //does not crash }

Try that with another reference type, eg a class with a length member.
Try that with a struct (value type), you'll find you cannot assign null.

The problem is perhaps trying to think of an array as "strictly" a reference type or "strictly" a value type. It's not, it's a mix of the two, an attempt by Walter (successful IMO) to get the best performance possible, passed by reference, stored on the stack, nice syntax, etc.

I believe you should think of arrays as references with special abilities like overloaded = and [] operators, for example. If we had the ability to define an opEquals for classes I believe we could emulate arrays with classes. (I admit, I haven't tried, nor considered it thoughroughly)

That said, you could perhaps equally argue that you should think of them as structs which are passed by reference, can be set to null, can be compared to null, .. I think of them as references, it makes more sense to me.

> If D strings truly couldn't be null I would expect something like:
>
> // Declare p
> // p is initialized to empty (not null - it can never be null)
> char[] p;
>
> // Test for empty
> // A test for null makes no sense - p can never be null
> if (!p) {}

The distinction is perhaps fine: "strings" can be non-existant. non-existant is typically represented with null. "array references" cannot be null. Yet, arrays can represent non-existant. A contradiction? No, those statements are not directly contradictory because:
 - null is not the only way to represent non-existance (beside the point in this case)
 - the object (arrays) need not be null in all situations.

In our case point 2 is the relevant one. Arrays are null only when they need to be in order to behave like other reference types. Arrays are not null when you try to dereference them.

> What am I missing?

Maybe nothing, maybe something, who am I to say. I can only offer my opinion above.

Regan
July 24, 2005
Hi,

In article <dc1689$h1q$1@digitaldaemon.com>, James McComb says...
>
>Regan Heath wrote:
>
>>> What do you mean by can't be null?
>> 
>> char[] p = null;
>> if (p.length == 0) { //does not crash, p itself is never 'null' }
>
>Okay... I obviously don't get D strings because this seems wildly counter-intuitive to me. Sure if p CANNOT be null, the line
>
>char[] p = null; // Surely this means: set p to null
>
>should fail to compile or throw an exception or something?

You are right, it is a little counter-intuitive. Then you say array = null you are sort of talking about the array's pointer, not the reference itself. I suspect one of two things happens internally:

1) The " = null" is simply ignored by the compiler (for efficiency). So
char[] p = null;
becomes:
char[] p;

2) A *new* reference (null pointer, 0-length) is created, in the style of function parameters, and assigned. In other words, it does whatever it does when you pass "null" to a function expecting an array.

>If D strings truly couldn't be null I would expect something like:
>
>// Declare p
>// p is initialized to empty (not null - it can never be null)
>char[] p;
>
>// Test for empty
>// A test for null makes no sense - p can never be null
>if (!p) {}
>
>What am I missing?

That's one of the original points of this thread. I wanted D to outlaw that test precisely because of the confusion. It didn't make sense to me either. You can think of "if (!p)" as "if (!p.ptr)". It is _not_ a test for emptiness. Therefore, I'm against this automatic conversion, for what it's worth.

Cheers,
--AJG.


July 25, 2005
Regan Heath wrote:

> ... the important fact here is that  though an array reference itself cannot be null it still behaves like any  other reference set to null ...
> with the exception that you can de-reference an array that has been  set to null ...

Thanks for the examples. I understand what you mean, now.

Considering that these lines are valid:

char[] p = null;
if (p is null) { //true }

...it confused me that you say p cannot be null.

I know what you mean now, though. :)

James McComb
July 25, 2005
On Mon, 25 Jul 2005 11:33:58 +1000, James McComb wrote:

> Regan Heath wrote:
> 
>> ... the important fact here is
>> that  though an array reference itself cannot be null it still behaves
>> like any  other reference set to null ...
>> with the exception that you can de-reference an array that has been
>> set to null ...
> 
> Thanks for the examples. I understand what you mean, now.
> 
> Considering that these lines are valid:
> 
> char[] p = null;
> if (p is null) { //true }
> 
> ...it confused me that you say p cannot be null.
> 
> I know what you mean now, though. :)

These lines are equivalent to ...

  char[] p;
  p.ptr = null;
  p.length = 0;
  if (p.ptr == null or p.length == 0) { //true }

I know Regan talks about an 'array reference' as an abstract concept but I just find it easier to think of it in terms of how it is actually implemented, namely a two field struct. To me, I keep thinking of a 'reference' as the address of a pointer - but that's just me ;-)

For example, '&p' returns the address of the array reference (struct) and
you can manipulate it directly (at your peril, of course).

-- 
Derek
Melbourne, Australia
25/07/2005 12:56:21 PM
July 27, 2005
AJG schrieb:
> You are right, it is a little counter-intuitive. Then you say array =
>  null you are sort of talking about the array's pointer, not the reference itself. I suspect one of two things happens internally:

> 2) A *new* reference (null pointer, 0-length) is created, in the style of function parameters, and assigned. In other words, it does whatever it does when you pass "null" to a function expecting an array.

You cannot say "new" because the array (slice) does not have the
reference sematics by itself, and does not get allocated. It is stored
inline - that is, wherever you mention it - on stack, within a class,
etc, as a *value*.

The statement "char[]p = null" declares an array slice on the stack (the
LHS), and at the same time assigns null to its pointer field, and 0 to
its length field.

The slice has a reference semantics with respect to its referred
elements, i.e. you can manipulate the elements directly and the changes propagate outside. However, it does not have a reference semantics in respect to its fields:

void manipulate(char[] blah) {
	assert(blah.length > 1);
	blah[0] = 'x'; //This change propagates
	blah.length = blah.length-1;
	//Above change does not propagate
	blah[0] = 'y'; //This change propagates
	blah~="z";
	//Above statement decouples completely
	//Now no changes will ever propagate,
	//whatever you do to the poor array!
}

I happen to like the strange semantics, but this is in strong contrast
to a string& or vector<blah>& in C++ or the Java array.

> 1) The " = null" is simply ignored by the compiler (for efficiency). So char[] p = null; becomes: char[] p;

I don't see any special provision for efficiency, just that an array
slice has a default value tuple (null,0), and the same gets assigned to
it by an assignment of null.

-eye
July 27, 2005
In article <dc86pk$2rta$1@digitaldaemon.com>, Ilya Minkov says...
>
>AJG schrieb:
>> You are right, it is a little counter-intuitive. Then you say array =
>>  null you are sort of talking about the array's pointer, not the
>> reference itself. I suspect one of two things happens internally:
>
>> 2) A *new* reference (null pointer, 0-length) is created, in the style of function parameters, and assigned. In other words, it does whatever it does when you pass "null" to a function expecting an array.
>
>You cannot say "new" because the array (slice) does not have the reference sematics by itself, and does not get allocated. It is stored inline - that is, wherever you mention it - on stack, within a class, etc, as a *value*.

I meant at compile-time, not in the "new int[5]" sense.

>The slice has a reference semantics with respect to its referred elements, i.e. you can manipulate the elements directly and the changes propagate outside. However, it does not have a reference semantics in respect to its fields:

I had been wondering how to define reference semantics for a while, and I think your definition is spot-on.

>I happen to like the strange semantics, but this is in strong contrast to a string& or vector<blah>& in C++ or the Java array.

I don't like the strange array field semantics. I ran into a particularly nasty length problem a couple of days ago, and life would have been much simpler if fields worked just like contents.

My solution was to use an array-reference pointer. E.g.

# alias char[] string;
# string original; // = whatever.
# string* trueReference = &original;
# trueReference.length = 5; // This does work properly.

>> 1) The " = null" is simply ignored by the compiler (for efficiency). So char[] p = null; becomes: char[] p;
>
>I don't see any special provision for efficiency, just that an array slice has a default value tuple (null,0), and the same gets assigned to it by an assignment of null.

What I meant is that char[] p; is already initialized to null. Doing an additional = null is redundant and thus eliminating it would be a small efficiency gain (again, to the compiler, not the runtime).

----

While we are on this topic, is this legal? (and safe?):

# void Foo (string s) {
#     assert(s.length == 3);
#     s[0] = 'F';
#     s[1] = 'o';
#     s[2] = 'o';
# }
#
# void Bar () {
#     string s = "Bar"; // Static data?
#     writefln(s);
#     Foo(s);
#     writefln(s);
# }

I think it should be, for consistency and simplicity, but I don't know about the safety of it. I don't have DMD handy to test it, either.

Thanks,
--AJG.


1 2 3 4 5 6 7
Next ›   Last »