digitalmars.D - For 2.0, or D++: A Thought about Class References & Pointers
- Russ Lewis (60/60) Aug 25 2004 I'm becoming increasingly convinced that not requiring * for class
- Sean Kelly (15/23) Aug 25 2004 While I'm a C/C++ person, I don't agree with this argument. The same co...
- Russ Lewis (23/33) Aug 26 2004 I understand that argument; yet I ask the question: why design a
- Matthias Becker (6/14) Aug 26 2004 What about the inconsitency of op= ? Sometimes it's a flat copy sometime...
- Russ Lewis (11/27) Aug 26 2004 I'm not 100% clear whether you're agreeing with me, or arguing. :) So
- Ilya Minkov (42/72) Aug 26 2004 The official position by Walter was that one usually needs 2 templates
- Russ Lewis (2/10) Aug 26 2004 Oops! Yes, of course, you're right.
- Ilya Minkov (4/5) Aug 26 2004 I had thought that thus the rest of my answer (correctly) assumes you
- Sai (111/111) Aug 26 2004 I guess the problem is with consistancy,
- Sai (32/32) Aug 26 2004 I am sorry, the HTML didn't get formatted, may be this whole message
- Sai (39/39) Aug 26 2004 I am sorry again ...... it looks like the lines got truncated
- Jarrett Billingsley (7/7) Aug 28 2004 i think i'm going to have to agree with russ on this one. the implicit
- Ben Hinkle (17/28) Aug 28 2004 Why are there two versions? If Foo is a struct and Bar is a class then t...
- Mike Swieton (9/28) Aug 29 2004 Syntactically, they're the same. You run into problems though, with refe...
- Russ Lewis (11/23) Aug 29 2004 Yes, that template works fine. But what about this one?
- Ben Hinkle (7/33) Aug 29 2004 That template also "works fine". I don't think the argument is over what
- Russ Lewis (10/47) Aug 30 2004 Classes and structs don't do the same thing, and I agree with you that
- Ilya Minkov (10/13) Aug 30 2004 You don't declare a *pointer* to the other, just that other is a
- Matthias Becker (25/36) Sep 02 2004 Perhaps I'm wrong, but that's not the point.
- Regan Heath (15/38) Sep 02 2004 So you don't think template specialisation solves them?
- Sean Kelly (20/26) Sep 02 2004 I'll admit I'm not entirely comfortable with the reference semantics for...
- Russ Lewis (3/7) Sep 03 2004 Perhaps a template called ReferenceTo() or PointerTo() which gives the
- Sha Chancellor (7/17) Aug 31 2004 Because one is on the stack, and the other is on the heap. And
- ninjadroid (43/43) Sep 01 2004 I certainly am not qualified to weigh in here, but here goes...
- Russ Lewis (10/10) Sep 01 2004 I think that your post is a good summary of many of the great features
- Regan Heath (25/58) Sep 01 2004 Here are your reasons again, and my thoughts on them:
- ninjadroid (28/32) Sep 02 2004 Good call, I'm sorry about that. Let me rectify this situation:
- Regan Heath (49/58) Sep 02 2004 Here is a simplified example showing what I personally encountered:
- ninjadroid (4/13) Sep 02 2004 That strikes me as the closest you're gonna get to The Right Thing. I a...
I'm becoming increasingly convinced that not requiring * for class reference variables was a mistake. In other words, I think that the syntax for declaring a new class variable on the heap should have been: MyClass *ptr = new MyClass; Note that I'm not suggesting that you should be able to use class variables directly (since that would require copy constructors and other nightmares) - instead, I'm suggesting that we keep the same language semantics, but simply require a '*' for all class reference variables. I have a couple of reasons for this: 1) Templates The first one I remember coming across was template code. Say you want to work with something by reference. If the thing is a class, then you must use the syntax "T foo" while if it is anything else, you must use the syntax "T* foo". It would be better if there was consistency. If there is an '*', then it is a pointer to something. If there is not, then it is a literal variable. 2) Newbie learning curve Many people have posted questions on the newsgroup, asking why their code segfaults when they write code like this: MyClass foo; foo.DoStuff(); We don't know how many more people just got turned off to D and never asked the question here. If the '*' were required, then newbies would learn quickly that the right thing to do is: MyClass *foo = new MyClass; foo.DoStuff(); 3) Objects on Heap We've had many long discussions about objects on the heap. The fact that D lacked them lead to 'auto' variables, and still people want more. Frankly, I think that objects on the heap make a lot of sense sometimes; we could have them and still avoid the copy constructor stuff. What if the compiler let you write this code: MyClass foo; which was syntax sugar for this: /* on stack */ MyClass _implicit_foo; /* ref */ MyClass *foo = &_implicit_foo; The class object would be constructed on the stack. Like 'auto', it would be automatically destroyed when the variable goes out of scope. The 'foo' variable would work pretty much like an "out" parameter to a function. Internally, it would be a pointer; however, you could use it like a value variable. So you could write this code: MyClass foo; MyClass *ptr = &foo; Moreover, you make these rules: * It is illegal to ever assign a value to a class variable. (You can assign values to pointers to classes.) So this code is illegal: MyClass a,b; a = b; /* syntax error */ * You can never have a class variable as a function arg. (You can have a pointer to a class as an arg.) Then, we don't have the copy constructor problem. If you want to pass an object to a function, you must pass a pointer to it, not the actual value. ***NOTE NOTE NOTE NOTE*** I want to say that I am still very much in support of D. I think that it is the best language out there (by far) and I use it as much as I'm able. So please, I'm not saying that "D is broken" - far from it. However, I think that the next generation language, be it D 2.0 or D++, should consider this argument and maybe make the change.
Aug 25 2004
In article <cgj8er$2lat$1 digitaldaemon.com>, Russ Lewis says...1) TemplatesWhat about "inout T foo"2) Newbie learning curveWhile I'm a C/C++ person, I don't agree with this argument. The same could be said of Java and yet folks have picked it up easily enough. I think this is just a language detail that people have to learn.3) Objects on Heap We've had many long discussions about objects on the heap. The fact that D lacked them lead to 'auto' variables, and still people want more.I think all people want is some guarantee that an auto object they construct is on the stack, and that is something I am not convinced is necessary. If something is declared as auto then I think it's fair to let the compiler decide where to put it. The stack is a completely viable option for compilers who want to optimize performance a bit.Then, we don't have the copy constructor problem. If you want to pass an object to a function, you must pass a pointer to it, not the actual value.I don't know, I kind of like D's current semantics. But it might be interesting to experiment with some sort of official copy constructor semantics. Or perhaps COW is the way to go for most instances. Either way, I'm not sure I'm keen on bringing more C pointer terminology into D than it already has. Sean
Aug 25 2004
Sean Kelly wrote:In article <cgj8er$2lat$1 digitaldaemon.com>, Russ Lewis says...And if you declare local variables? inout doesn't help me then.1) TemplatesWhat about "inout T foo"I understand that argument; yet I ask the question: why design a language element such that people "have" to learn it? Why do something that almost guarantees that people coming from C++ will struggle with segfaults for a while before they get working code? I think that if we do what I suggest here, the compiler can instruct the coder with its syntax error messages: If we don't allow objects on the stack (as below), then when a newbie first writes: MyClass foo; the compiler can respond with an error "ERROR: Class objects cannot be allocated on the heap. Use a pointer variable, and allocate an object with operator new instead." Bingo! The newbie immediately knows what to do, with no segfaults. OTOH, if we allow objects on the heap, then C++ programmers come over and it just works the way they expect. The first time that they try to assign something: MyClass bar,baz; bar = baz; the compiler can tell them "ERROR: Class variables cannot be assigned. Use pointers to classes instead." And now the C++ programmers know exactly how to use the language as well.2) Newbie learning curveWhile I'm a C/C++ person, I don't agree with this argument. The same could be said of Java and yet folks have picked it up easily enough. I think this is just a language detail that people have to learn.
Aug 26 2004
I have a couple of reasons for this: 1) Templates The first one I remember coming across was template code. Say you want to work with something by reference. If the thing is a class, then you must use the syntax "T foo" while if it is anything else, you must use the syntax "T* foo". It would be better if there was consistency. If there is an '*', then it is a pointer to something. If there is not, then it is a literal variable.What about the inconsitency of op= ? Sometimes it's a flat copy sometimes a reference assignment. So do we then get foo = bar; // reference assignment *foo = *bar; // flat copy ???
Aug 26 2004
Matthias Becker wrote:I'm not 100% clear whether you're agreeing with me, or arguing. :) So I'll try to state my view about this subject... This example is just another reason why lacking the '*' makes templates hard to write. If you write this code: template <T> void foo(T arg) { T mine = arg; ... } is 'mine' a copy of the value in arg, or a copy of a reference? It would be better if we knew if we were assigning a reference or a value.I have a couple of reasons for this: 1) Templates The first one I remember coming across was template code. Say you want to work with something by reference. If the thing is a class, then you must use the syntax "T foo" while if it is anything else, you must use the syntax "T* foo". It would be better if there was consistency. If there is an '*', then it is a pointer to something. If there is not, then it is a literal variable.What about the inconsitency of op= ? Sometimes it's a flat copy sometimes a reference assignment. So do we then get foo = bar; // reference assignment *foo = *bar; // flat copy ???
Aug 26 2004
Russ Lewis schrieb:I'm becoming increasingly convinced that not requiring * for class reference variables was a mistake. In other words, I think that the syntax for declaring a new class variable on the heap should have been: MyClass *ptr = new MyClass;Yikes.I have a couple of reasons for this: 1) TemplatesThe official position by Walter was that one usually needs 2 templates in the case of classes and structs. In general, i think templates play an important role in D by allowing to parametrically duplicate some code - something that wasn't possible in Delphi and thus would lead to unsafe containers or every project having to write out (duplicate manually) ThisTypeList and ThatTypeList and ThisTypeBlah in masses - that's what we get to avoid. But i'm not so sure that making templates have the same role as in C++, being the universal hole-filler for everything, makes much sense.2) Newbie learning curveThe newbies would just not learn D if we do as you suggest. :) Pointer on classes and combined struct/ class semantics is one of the most confusing things for newbees in C++, so the Delphi and Java syntax/ semantics like we have now is much newbee-safer. But your suggestion is by far more confusing, i believe. I just try to put myself in the position of a newbee. Another thing is that if we do as you suggest, people coming from C++ would requiere that we implement a complete C++ struct/class semantics, and not just allow to use objects by pointer.3) Objects on Heap We've had many long discussions about objects on the heap. The fact that D lacked them lead to 'auto' variables, and still people want more. Frankly, I think that objects on the heap make a lot of sense sometimes; we could have them and still avoid the copy constructor stuff.Objects on the heap? they are on the heap. Perhaps you mean on the stack? And hey, it is so common to read in C++ libraries "do not construct this on the stack else this breaks". There are just so many things that are better off being on the heap - especially in D where the performance of the garbage collector scan can be severely improved for the heap but not much for the stack. Besides, the implementation would be with hoops and advert effect on performance, since D tries to reduce the number of implicit finalization blocks which are inserted by C++ all over the place. That's apparently the reason why Walter doesn't want structs to have destructors. Perhaps some better support for auto classes would be desired. I'd say it's preferred against adding more stack functionality to usual classes or destructors to structs, since it will not have the "surprising" advert performance effect, and the usage is somewhat better documented that way. And it's less ugly. :)Moreover, you make these rules: * It is illegal to ever assign a value to a class variable. (You can assign values to pointers to classes.) So this code is illegal: MyClass a,b; a = b; /* syntax error */ * You can never have a class variable as a function arg. (You can have a pointer to a class as an arg.) Then, we don't have the copy constructor problem. If you want to pass an object to a function, you must pass a pointer to it, not the actual value.Hmmm. What it all gives us, that we have to decorate all the common usage cases with a "*", and where the traditional syntax is left it is a bug. If we do anything like that, it should be with a special syntax for the special case, not the other way around.***NOTE NOTE NOTE NOTE*** I want to say that I am still very much in support of D. I think that it is the best language out there (by far) and I use it as much as I'm able. So please, I'm not saying that "D is broken" - far from it. However, I think that the next generation language, be it D 2.0 or D++, should consider this argument and maybe make the change.Noone is accusing you of anything. After all, it is just opinions. Luckily, we have Walter who would not let anyone just spoil his language. :) -eye
Aug 26 2004
Ilya Minkov wrote:Oops! Yes, of course, you're right.3) Objects on Heap We've had many long discussions about objects on the heap. The fact that D lacked them lead to 'auto' variables, and still people want more. Frankly, I think that objects on the heap make a lot of sense sometimes; we could have them and still avoid the copy constructor stuff.Objects on the heap? they are on the heap. Perhaps you mean on the stack?
Aug 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
Aug 26 2004
I guess the problem is with consistancy, Either be consistent in syntax for (stack or heap based) memory allocations or mention it clearly in documentation all possible syntaxes. We have none right now. Few pages of HTML documentation with scattered information without search facility is really discouraging. I have complete faith in Walter, I believe what ever he has decided on syntax there must be some rationale for it. So I would be very happy if Walter or some one could dedicate a page on all possible syntaxes. Being a proactive person, let me start first. Please correct me if I am wrong, and please add entries of I missed some syntaxes. (I am trying to embed HTML in this post) <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: <tr> <td width="54%"><i><b>Syntax</b></i></td> <td width="21%"><i><b>'var' is reference or 'value' ?</b></i></td> <td width="28%"><i><b>if reference,<br> is memory allocated ?</b></i></td> </tr> <tr> <td width="54%"><i><b>For Classes</b></i></td> <td width="21%"> </td> <td width="28%"> </td> </tr> <tr> <td width="54%">Class_type var;</td> <td width="21%">reference</td> <td width="28%">no</td> </tr> <tr> <td width="54%">Class_type var = new Class_type();</td> <td width="21%">reference</td> <td width="28%">yes</td> </tr> <tr> <td width="54%"> </td> <td width="21%"> </td> <td width="28%"> </td> </tr> <tr> <td width="54%"><i><b>For Structs</b></i></td> <td width="21%"> </td> <td width="28%"> </td> </tr> <tr> <td width="54%">Struct_type var;</td> <td width="21%">value</td> <td width="28%">-</td> </tr> <tr> <td width="54%">Struct_type* var;</td> <td width="21%">reference</td> <td width="28%">no</td> </tr> <tr> <td width="54%">Struct_type* var = new Struct_type;</td> <td width="21%">reference </td> <td width="28%">yes</td> </tr> <tr> <td width="54%"> </td> <td width="21%"> </td> <td width="28%"> </td> </tr> <tr> <td width="54%"><i><b>For Arrays</b></i></td> <td width="21%"> </td> <td width="28%"> </td> </tr> <tr> <td width="54%">Static_array[100] var;</td> <td width="21%">reference</td> <td width="28%">yes</td> </tr> <tr> <td width="54%">Dynamic_array[] var;</td> <td width="21%">reference</td> <td width="28%">yes</td> </tr> <tr> <td width="54%">Dynamic_array[] var = new Dynamic_array[]; </td> <td width="21%">reference</td> <td width="28%">yes</td> </tr> <tr> <td width="54%"> </td> <td width="21%"> </td> <td width="28%"> </td> </tr> <tr> <td width="54%"><i><b>For Primitives</b></i></td> <td width="21%"> </td> <td width="28%"> </td> </tr> <tr> <td width="54%">Primitive_type var; </td> <td width="21%">value</td> <td width="28%">-</td> </tr> <tr> <td width="54%">Primitive_type* var;</td> <td width="21%">reference</td> <td width="28%">no</td> </tr> <tr> <td width="54%"> </td> <td width="21%"> </td> <td width="28%"> </td> </tr> </table>
Aug 26 2004
I am sorry, the HTML didn't get formatted, may be this whole message is in <pre> tags. here is the text version --------------------------------------------------------------------------------------------- Syntax 'var' is reference if reference, or 'value' ? is memory allocated ? ---- For Classes ---------------------------------------------------------------------------- Class_type var; reference no Class_type var = new Class_type(); reference yes ---- For Structs ---------------------------------------------------------------------------- Struct_type var; value - Struct_type* var; reference no Struct_type* var = new Struct_type; reference yes ---- For Arrays ---------------------------------------------------------------------------- Static_array[100] var; reference yes Dynamic_array[] var; reference yes Dynamic_array[] var = new Dynamic_array[]; reference yes ---- For Primitives ------------------------------------------------------------------------- Primitive_type var; value - Primitive_type* var; reference no ---------------------------------------------------------------------------------------------
Aug 26 2004
I am sorry again ...... it looks like the lines got truncated after 80(?) characters on a line. Here is another version .... looks better and easy to add more entries. ---- For Classes --------------------------------------- Syntax : Class_type var; Reference or value : reference if reference is memory allocated : no Syntax : Class_type var = new Class_type(); Reference or value : reference if reference is memory allocated : yes ---- For Structs --------------------------------------- Syntax : Struct_type var; Reference or value : value if reference is memory allocated : - Syntax : Struct_type* var; Reference or value : reference if reference is memory allocated : no Syntax : Struct_type* var = new Struct_type; Reference or value : reference if reference is memory allocated : yes ---- For Arrays --------------------------------------- Syntax : Static_array[100] var; Reference or value : reference if reference is memory allocated : yes Syntax : Dynamic_array[] var; Reference or value : reference if reference is memory allocated : yes Syntax : Dynamic_array[] var = new Dynamic_array[]; Reference or value : reference if reference is memory allocated : yes ---- For Primitives ------------------------------------ Syntax : Primitive_type var; Reference or value : value if reference is memory allocated : - Syntax : Primitive_type* var; Reference or value : reference if reference is memory allocated : no --------------------------------------------------------
Aug 26 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.
Aug 28 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
Aug 28 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!) -BenSyntactically, 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
Aug 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?
Aug 29 2004
Russ Lewis wrote:Ben Hinkle wrote: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.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?
Aug 29 2004
Ben Hinkle wrote:Russ Lewis 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?Ben Hinkle wrote: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.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?
Aug 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, -eye
Aug 30 2004
Perhaps I'm wrong, but that's not the point. We talked about templates which are hard to maintain because the same synthax has different meanings but templates are about writing general code, that can be used everywhere. This thread was only about a suggestion to make the language mor consistent. I don't realy like this idea, but it is still a way to solve the problems that you have when you write template-code. Perhaps we wouldhave needed a different synthax way before. But I think now it's to late for big changes. We could have done something like this: "name" means the value of something, "&name" means the address of something. So to do a value-assignment you write "name1 = name2", to do a reference-assignment you write "&name1 = &name2". On a value-type "&name" is just constant, so you can't assign a new adress, while it's mutable on reference-objects. This way we would have a very consistent notation. ValueType vtFoo, vtBar; ReferenceType rtFoo, rtBar; vtFoo = vtBar; // value-assignemtn &vtFoo = &vtBar; // impossible, &vtFoo isn't an l-value rtFoo = rtBar; // not sure, eigther this isn't allowed or we'd need a opAssign, which would be very constent to havving +=, -=. *=, ... overloadable &rtFoo = &rtBar; // reference-assignment This way the same notation would allways refere to the same thing, so writing template code would be very easy. -- Matthias BeckerSo, 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,
Sep 02 2004
On Thu, 2 Sep 2004 14:45:00 +0000 (UTC), Matthias Becker <Matthias_member pathlink.com> wrote:So you don't think template specialisation solves them? It just occured to me that "specialisation" is almost the opposite of "generic", and D's solution (C/C++ also) to the "generic" problem is to be less generic. Perhaps this is a bad thing, or perhaps it's the natural result of having 'different' types which simply cannot be treated 'generically'. You could wrap all the native types in classes, then you would have a bunch of types you could treat generically. It seems to me that is what is required to enable truly generic programming. That and perhaps a less strict type sort of language. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/Perhaps I'm wrong, but that's not the point. We talked about templates which are hard to maintain because the same synthax has different meanings but templates are about writing general code, that can be used everywhere. This thread was only about a suggestion to make the language mor consistent. I don't realy like this idea, but it is still a way to solve the problems that you have when you write template-code.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,
Sep 02 2004
In article <opsdp0visx5a2sq9 digitalmars.com>, Regan Heath says...Perhaps this is a bad thing, or perhaps it's the natural result of having 'different' types which simply cannot be treated 'generically'. You could wrap all the native types in classes, then you would have a bunch of types you could treat generically.Perhaps we should just all use Smalltalk ;)It seems to me that is what is required to enable truly generic programming. That and perhaps a less strict type sort of language.I'll admit I'm not entirely comfortable with the reference semantics for class obejcts in D, but I don't know that there's an easy fix on the language side. What I will probably end up doing is use a bunch of little utility templates that are specialized to guarantee expected behavior. However I think classes are the odd man out in this case. Arrays may use references but they have COW semantics, while classes do not. In some respects it would be kind of interesting to have the language support limited COW semantics for classes as well. Perhaps call a copy ctor if a "watched" (ie. non-const) member function is called on a shared object. So you could declare a class this way: Frankly, I'm not sure how useful this would be, but I thought I'd mention it anyway as it's not something I've seen in a language before. Sean
Sep 02 2004
Sean Kelly wrote:I'll admit I'm not entirely comfortable with the reference semantics for class obejcts in D, but I don't know that there's an easy fix on the language side. What I will probably end up doing is use a bunch of little utility templates that are specialized to guarantee expected behavior.Perhaps a template called ReferenceTo() or PointerTo() which gives the reference type for any given type?
Sep 03 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.
Aug 31 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.
Sep 01 2004
I think that your post is a good summary of many of the great features about D. And in the past, I agreed with you: let's do away with pointers in favor of more automatic and safe constructs. I still think that way, at the semantic level. I'm not suggesting that it should be possible to do pointer arithmetic on class references, or anything funky like that. But did you read my original post (the one that started this thread)? I've come across a few reasons - that IMHO are fairly compelling - why class references should use pointer syntax. What do you think about those reasons?
Sep 01 2004
On Wed, 01 Sep 2004 10:49:37 -0700, Russ Lewis <spamhole-2001-07-16 deming-os.org> wrote:I think that your post is a good summary of many of the great features about D. And in the past, I agreed with you: let's do away with pointers in favor of more automatic and safe constructs. I still think that way, at the semantic level. I'm not suggesting that it should be possible to do pointer arithmetic on class references, or anything funky like that. But did you read my original post (the one that started this thread)? I've come across a few reasons - that IMHO are fairly compelling - why class references should use pointer syntax. What do you think about those reasons?Here are your reasons again, and my thoughts on them:1) Templates The first one I remember coming across was template code. Say you want to work with something by reference. If the thing is a class, then you must use the syntax "T foo" while if it is anything else, you must use the syntax "T* foo". It would be better if there was consistency. If there is an '*', then it is a pointer to something. If there is not, then it is a literal variable.I agree, this is confusing, annoying and causes subtle bugs. I once changed the type used in a template from a class to a struct and created a bug, that took me 1/2 an hour to find. That said, I *like* the fact that we have 2 different types of object, one value type stack allocated object, and one reference type heap allocated (generally) object. Walter has added the ability for you to specify which types can be used in your templates, so, a well written template does not suffer from this problem any more. I suggested a little while back that modifying an 'in' parameter should be an error, if this were adopted then the compiler would have spotted the bug I created switching from a class to a struct, and most(all?) the bugs created by the differences using struct/class in templates. Basically I think the 2 different types are a good thing, and we can catch the bad things they can potentially cause.2) Newbie learning curve Many people have posted questions on the newsgroup, asking why their code segfaults when they write code like this: MyClass foo; foo.DoStuff();I believe the compiler could be improved to spot this obvious error, in which case this is no longer a problem.We don't know how many more people just got turned off to D and never asked the question here. If the '*' were required, then newbies would learn quickly that the right thing to do is: MyClass *foo = new MyClass; foo.DoStuff();3) Objects on Heap We've had many long discussions about objects on the heap. The fact that D lacked them lead to 'auto' variables, and still people want more. Frankly, I think that objects on the heap make a lot of sense sometimes; we could have them and still avoid the copy constructor stuff.We already have objects on the heap, via structs and 'auto' classes, and they work as you'd want them to work, I see no problem here. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Sep 01 2004
In article <ch523h$2etg$2 digitaldaemon.com>, Russ Lewis says...But did you read my original post (the one that started this thread)? I've come across a few reasons - that IMHO are fairly compelling - why class references should use pointer syntax. What do you think about those reasons?Good call, I'm sorry about that. Let me rectify this situation: 1) Templates I don't understand the practical implications of the problem you point out. The fact that objects have implicit reference semantics and structs don't doesn't seem to cause any tangible woes. I think that if the distinction was indeed problematic, it would have been discovered long ago in C++ since arrays and char/int/etc. have a similar distinction. Can you post a link to an example that demonstrates this problem? Length isn't an issue. Regardless, even if there are situations where the different semantics cause a problem in the context of templates, I'd wager that they are very few in number, and infinitesimal in a relative sense. Now that D can specify which types are allowable in a template, such exceptional circumstances can be handled. It's obviously not a perfect method, but I believe it is optimal. It's best to make those scenarios which represent 99% of use cases easier at the expense of the 1% fringe than vice versa. (Although it does frost my cherries when I happen to find myself in that 1% :-) 2) Newbie learning curve The compiler should flag this as an error, plain and simple. On a similar note, I've been giving this some more thought, and I really think that having the 'in' keyword designate strict enforcement (changing the variable is an error) is The Right Thing. That, combined with encouraging new programmers to *always* specify in, out, or inout should mask the confusion of implicit/explicit reference semantics completely. If the in keyword is omitted, then things can behave as usual to prevent the frustration of experienced users. 3) Objects on the [Stack] I think the combination of the 'auto' keyword and garbage collection obviate the need for this; there simply isn't any benefit.
Sep 02 2004
On Thu, 2 Sep 2004 16:06:06 +0000 (UTC), ninjadroid <ninjadroid_member pathlink.com> wrote:In article <ch523h$2etg$2 digitaldaemon.com>, Russ Lewis says... 1) Templates I don't understand the practical implications of the problem you point out. The fact that objects have implicit reference semantics and structs don't doesn't seem to cause any tangible woes. I think that if the distinction was indeed problematic, it would have been discovered long ago in C++ since arrays and char/int/etc. have a similar distinction. Can you post a link to an example that demonstrates this problem? Length isn't an issue.Here is a simplified example showing what I personally encountered: template t(T) { void change(T a) { a.prop++; } } class A { int prop; } struct B { int prop; } void main() { A a = new A(); B b; //a.prop == 0 t!(A).change(a); //a.prop now == 1 //b.prop == 0 t!(B).change(b); //b.prop now == 0; } of course this is simplified and it's easy to see what is happening, the real case was much more complicated. That said, I think template specialisation solves this problem eg. template t(T : class) { void change(T a) { a.prop++; } } does the above allow you to use it with other 'reference' types eg the built in arrays? if not perhaps a 'value' or 'reference' keyword in template specialisation would be nice eg. template t(T : reference) { void change(T a) { a.prop++; } } Another solution is to change the template to template t(T) { void change(inout T a) { a.prop++; } } in other words pass the struct by reference. I believe checking 'in' parameters are not modified would have spotted this bug for me, I still advocate this change. Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Sep 02 2004
In article <opsdpz09y05a2sq9 digitalmars.com>, Regan Heath says...Another solution is to change the template to template t(T) { void change(inout T a) { a.prop++; } } in other words pass the struct by reference. I believe checking 'in' parameters are not modified would have spotted this bug for me, I still advocate this change.That strikes me as the closest you're gonna get to The Right Thing. I also think it solidifies the case for strictly enforcing in parameters! Is there any reason not to?
Sep 02 2004