August 26, 2004
Russ Lewis schrieb:

> Oops!  Yes, of course, you're right.

I had thought that thus the rest of my answer (correctly) assumes you meant what you meant.

-eye
August 29, 2004
i think i'm going to have to agree with russ on this one.  the implicit extra level of indirection has bitten me in the ass more than a few times, it's inconsistent, and it seems stupid to have to define 2 versions of a template, especially if they have virtually no differences.  i'm not so sure what's so evil about Object* o=new Object.  at least i know it's a pointer.

like you said russ, it would be great if it denied you from creating objects on the STACK ;)  but still used the pointer syntax.


August 29, 2004
Jarrett Billingsley wrote:

> i think i'm going to have to agree with russ on this one.  the implicit
> extra level of indirection has bitten me in the ass more than a few times,
> it's inconsistent, and it seems stupid to have to define 2 versions of a
> template, especially if they have virtually no differences.  i'm not so
> sure
> what's so evil about Object* o=new Object.  at least i know it's a
> pointer.
> 
> like you said russ, it would be great if it denied you from creating
> objects
> on the STACK ;)  but still used the pointer syntax.

Why are there two versions? If Foo is a struct and Bar is a class then the
following template works fine:
template baz(T) {
  void baz(T x) { x.y = 10; }
}
baz!(Foo*)(&x1);
baz!(Bar)(x2);
baz!(Foo)(x3); // this call doesn't do anything interesting, though

The beauty is that the "." operator works through references and pointers - a template that just reads x would be able to work with Foo in addition to Foo* but one that changes x needs to have reference semantics.

I've always thought it was silly for C++ to have two constructs (struct and class) that mean 99% the same thing and just differ in default visibility. A lost opportunity that Java corrected (well, except they forgot about struct!)

-Ben
August 29, 2004
On Sat, 28 Aug 2004 22:12:25 -0400, Ben Hinkle wrote:
> Why are there two versions? If Foo is a struct and Bar is a class then the
> following template works fine:
> template baz(T) {
>   void baz(T x) { x.y = 10; }
> }
> baz!(Foo*)(&x1);
> baz!(Bar)(x2);
> baz!(Foo)(x3); // this call doesn't do anything interesting, though
> 
> The beauty is that the "." operator works through references and pointers - a template that just reads x would be able to work with Foo in addition to Foo* but one that changes x needs to have reference semantics.
> 
> I've always thought it was silly for C++ to have two constructs (struct and class) that mean 99% the same thing and just differ in default visibility. A lost opportunity that Java corrected (well, except they forgot about struct!)
> 
> -Ben

Syntactically, they're the same. You run into problems though, with reference vs. value semantics.

Mike Swieton
__
Q: That said, do you have any ideas for a really scary reality TV show?
A: "C Students from Yale." It would stand your hair on end.
	- Joel Bleifuss interviewing author Kurt Vonnegut
	  In These Times, 1/27/03

August 29, 2004
Ben Hinkle wrote:
> Why are there two versions? If Foo is a struct and Bar is a class then the
> following template works fine:
> template baz(T) {
>   void baz(T x) { x.y = 10; }
> }
> baz!(Foo*)(&x1);
> baz!(Bar)(x2);
> baz!(Foo)(x3); // this call doesn't do anything interesting, though
> 
> The beauty is that the "." operator works through references and pointers -
> a template that just reads x would be able to work with Foo in addition to
> Foo* but one that changes x needs to have reference semantics.

Yes, that template works fine.  But what about this one?

template baz(T) {
  void baz(T x) {
    T temp = x;
    temp.y = 10;
    return temp;
  }
}

Was that assignment an assignment by reference or value?  Has the function modified the value of y in any external object?

August 29, 2004
Russ Lewis wrote:

> Ben Hinkle wrote:
>> Why are there two versions? If Foo is a struct and Bar is a class then
>> the following template works fine:
>> template baz(T) {
>>   void baz(T x) { x.y = 10; }
>> }
>> baz!(Foo*)(&x1);
>> baz!(Bar)(x2);
>> baz!(Foo)(x3); // this call doesn't do anything interesting, though
>> 
>> The beauty is that the "." operator works through references and pointers - a template that just reads x would be able to work with Foo in addition to Foo* but one that changes x needs to have reference semantics.
> 
> Yes, that template works fine.  But what about this one?
> 
> template baz(T) {
>    void baz(T x) {
>      T temp = x;
>      temp.y = 10;
>      return temp;
>    }
> }
> 
> Was that assignment an assignment by reference or value?  Has the function modified the value of y in any external object?

That template also "works fine". I don't think the argument is over what templates do with structs and classes - it is about the fact that structs and classes have different semantics and as a side effect templates behave differently with one or the other. I argue having different semantics is a good thing. Why have two constructs that do the same thing? That is wasteful language design.
August 30, 2004
Ben Hinkle wrote:
> Russ Lewis wrote:
> 
> 
>>Ben Hinkle wrote:
>>
>>>Why are there two versions? If Foo is a struct and Bar is a class then
>>>the following template works fine:
>>>template baz(T) {
>>>  void baz(T x) { x.y = 10; }
>>>}
>>>baz!(Foo*)(&x1);
>>>baz!(Bar)(x2);
>>>baz!(Foo)(x3); // this call doesn't do anything interesting, though
>>>
>>>The beauty is that the "." operator works through references and pointers
>>>- a template that just reads x would be able to work with Foo in addition
>>>to Foo* but one that changes x needs to have reference semantics.
>>
>>Yes, that template works fine.  But what about this one?
>>
>>template baz(T) {
>>   void baz(T x) {
>>     T temp = x;
>>     temp.y = 10;
>>     return temp;
>>   }
>>}
>>
>>Was that assignment an assignment by reference or value?  Has the
>>function modified the value of y in any external object?
> 
> That template also "works fine". I don't think the argument is over what
> templates do with structs and classes - it is about the fact that structs
> and classes have different semantics and as a side effect templates behave
> differently with one or the other. I argue having different semantics is a
> good thing. Why have two constructs that do the same thing? That is
> wasteful language design.

Classes and structs don't do the same thing, and I agree with you that they shouldn't.  Structs are low-level constructs.  They don't have vtables, they don't have dynamic dispatching, etc.  They are pretty much like C structs, and give you the efficiency you sometimes need. Classes, on the other hand, are object oriented: they have dynamic dispatching, inheritance, interfaces, etc.

So, assuming that they *are* different, why is it a benefit that, when you declare a pointer to one you use the '*', and when you declare a pointer to the other, you don't?

August 30, 2004
Russ Lewis schrieb:

> So, assuming that they *are* different, why is it a benefit that, when you declare a pointer to one you use the '*', and when you declare a pointer to the other, you don't?

You don't declare a *pointer* to the other, just that other is a reference type! What is so hard about that? Like, if you pass an array you don't call it "pointer to an array with external length"... This is definately a point of view thing, but i'd say people thinking in "pointer to a class" (instead of "class is a pointer to underlying struct") are just spoiled by the thinking one certain language forces on its users, while *all* of the other languages i'm aware of (Delphi, Java, C#, even Sather) use the other one and their users don't complain!

-eye
August 31, 2004
In article <cgvrid$2pic$1@digitaldaemon.com>,
 Russ Lewis <spamhole-2001-07-16@deming-os.org> wrote:

> Classes and structs don't do the same thing, and I agree with you that they shouldn't.  Structs are low-level constructs.  They don't have vtables, they don't have dynamic dispatching, etc.  They are pretty much like C structs, and give you the efficiency you sometimes need. Classes, on the other hand, are object oriented: they have dynamic dispatching, inheritance, interfaces, etc.
> 
> So, assuming that they *are* different, why is it a benefit that, when you declare a pointer to one you use the '*', and when you declare a pointer to the other, you don't?

Because one is on the stack, and the other is on the heap.  And sometimes it's good to be explicit about what's going on.  Everything else that's on the heap requires a *.  Even a struct that's on the heap requires a little *.  Why not a class?  Just because a class CAN'T be on the stack?  Phhfftt.
September 01, 2004
I certainly am not qualified to weigh in here, but here goes...

I think that the current D syntax is superior because it will maximize consistency for the vast majority of uses.  It may seem out of place when you're still "thinking in C," but I think that the higher level constructs D provides obviate quite nearly all of the need for pointers.

C pointers serve 2 primary purposes, the first being providing reference semantics, and the second being providing a means for dynamic memory management. Taken in this context, the way D considers classes to be a reference type is indeed confusing, because you must use explicit pointer notation to get the same effect with other types.

The only exception is with arrays, which have reference semantics themselves. Now, think back to when you first started programming in C; didn't this confuse the hell out of you?  It certainly tripped me up, and occasionally catches me off guard to this day.  So, we should strive to avoid inconsistency in reference semantics.

With D, reference semantics are provided by a completely different method.  The in, out, and inout keywords do the job pointers did in C.  So requiring explicit pointer notation to indicate reference semantics actually introduces an inconsistency, since the Right Way to do the by-ref dance is *not* with pointers.[1]

As for memory allocation, D makes pointers unnecessary here as well, although the reason why isn't quite as obvious.  The most basic dynamic memory need is resizing an array of objects; the existence of a built in dynamic array type eliminates the need to create a custom solution here.

The next step up is with fundamental data structures, such as linked lists, which need a way of referring to other data containers.  [speculation starts here]  Now, it seems to me that these things will be best, and typically, implemented using objects.  Since objects have reference semantics, there is no need for a pointer here, you can new/delete all you want without ever encountering a * .

In a practical sense, the only reason you'll ever need to use pointers is because you're working with structs.  And the only reason you'll ever need to use structs is because you're doing very low level programming.  If we posit that people doing such programming know what their doing, then it isn't much a stretch to assume that they'll be able to deal with the juxtaposition of implicit and explicit reference semantics.

My $3.50, I hope that all made sense.

[1] This reminds me, is it an error to change the contents of an array that is passed as an "in" value?  If not, I think it should be, to avoid the kind of confusion that I mentioned above in regards to C arrays vs. other types.  Same goes for classes, and maybe even for fundamental types.  It might seem pedantic to do so, but experienced programmers certainly won't lose anything, and this "arbitrary roadblock" will help newbies avoid confusion.