Jump to page: 1 29  
Page
Thread overview
Hiding class pointers -- was it a good idea?
Aug 15, 2007
Bill Baxter
Aug 15, 2007
Jascha Wetzel
Aug 15, 2007
Deewiant
Aug 15, 2007
Bill Baxter
Aug 15, 2007
Deewiant
Aug 15, 2007
Bill Baxter
Aug 15, 2007
Deewiant
Aug 15, 2007
Sean Kelly
Aug 15, 2007
Tristam MacDonald
Aug 15, 2007
Gregor Richards
Aug 15, 2007
Bill Baxter
Aug 15, 2007
Gregor Richards
Aug 15, 2007
Regan Heath
Aug 15, 2007
Bill Baxter
Aug 15, 2007
Walter Bright
Aug 16, 2007
Bill Baxter
Aug 16, 2007
Leandro Lucarella
Aug 16, 2007
Walter Bright
Aug 15, 2007
Walter Bright
Aug 15, 2007
Gregor Richards
Aug 15, 2007
Walter Bright
Aug 16, 2007
James Dennett
Aug 16, 2007
Walter Bright
Aug 17, 2007
James Dennett
Aug 17, 2007
Don Clugston
Aug 17, 2007
Walter Bright
Aug 18, 2007
James Dennett
Aug 17, 2007
Alex Burton
Aug 17, 2007
Tristam MacDonald
Aug 18, 2007
Alex Burton
Aug 18, 2007
James Dennett
Aug 15, 2007
Reiner Pope
Aug 15, 2007
Bill Baxter
Aug 15, 2007
Russell Lewis
Aug 15, 2007
Tristam MacDonald
Aug 15, 2007
Russell Lewis
Aug 15, 2007
Johan Granberg
Aug 15, 2007
Walter Bright
Aug 16, 2007
James Dennett
Aug 16, 2007
Robert Fraser
Aug 16, 2007
Walter Bright
Aug 17, 2007
James Dennett
Aug 16, 2007
Walter Bright
Aug 17, 2007
James Dennett
Aug 17, 2007
Russell Lewis
Aug 17, 2007
Bill Baxter
Aug 16, 2007
James Dennett
Aug 15, 2007
Sean Kelly
Aug 15, 2007
Walter Bright
Aug 16, 2007
Brad Roberts
Aug 16, 2007
Walter Bright
Aug 16, 2007
Bill Baxter
Aug 16, 2007
Walter Bright
Aug 16, 2007
James Dennett
Aug 16, 2007
Bill Baxter
Aug 16, 2007
Walter Bright
Aug 17, 2007
James Dennett
Aug 17, 2007
Walter Bright
Aug 18, 2007
James Dennett
Aug 16, 2007
eao197
Aug 16, 2007
Bill Baxter
Aug 16, 2007
eao197
Aug 16, 2007
Matthias Walter
Aug 16, 2007
Walter Bright
Aug 16, 2007
eao197
Aug 16, 2007
eao197
Aug 16, 2007
Walter Bright
Aug 17, 2007
eao197
Aug 17, 2007
Jb
Aug 17, 2007
eao197
Aug 17, 2007
Jb
Aug 17, 2007
eao197
Aug 18, 2007
eao197
Aug 16, 2007
Stephen Waits
Aug 16, 2007
Walter Bright
Aug 16, 2007
kris
Aug 17, 2007
James Dennett
Aug 16, 2007
Jason House
Aug 16, 2007
Bill Baxter
Aug 16, 2007
Jason House
Aug 16, 2007
Bill Baxter
Aug 17, 2007
Russell Lewis
August 15, 2007
I'm starting to seriously wonder if it was a good idea to hide the pointers to classes.  It seemed kinda neat when I was first using D that I could avoid typing *s all the time.  But as time wears on it's starting to seem more like a liability.

Bad points:
- Harder to tell whether you're dealing with a pointer or not
  (c.f. the common uninitialized 'MyObject obj;' bug)
- To build on the stack, have to use 'scope'

Good points:
+ No need to type '*' everywhere when you use class objects
+ ??? anything else ???


I guess I feel like that if D were Java, I'd never see the pointers, "Foo foo;" would always mean a heap-allocated thing, and everything would be cool. But with D sometimes "Foo foo" means a stack allocated thing, and sometimes it doesn't.  I'm starting to think the extra cognitive load isn't really worth it.

In large part it all stems from the decision to make classes and structs different.  That seems nice in theory, but as time goes on the two are becoming more and more alike.  Classes can now be stack-allocated with scope.  Structs are supposedly going to get constructors, and maybe even destructors.  It kind of makes me think that maybe separating structs and classes was a bad idea.  I have yet to ever once say to myself "thank goodness structs and classes are different in D!", though plenty of times I've muttered "dangit why can't I just get a default copy constructor for this class" or "shoot, these static opCalls are annoying" or "dang, I wish I could get a weak reference to a struct", etc.

--bb
August 15, 2007
Bill Baxter wrote:
> I'm starting to seriously wonder if it was a good idea to hide the pointers to classes.  It seemed kinda neat when I was first using D that I could avoid typing *s all the time.  But as time wears on it's starting to seem more like a liability.
> 
> Bad points:
> - Harder to tell whether you're dealing with a pointer or not
>   (c.f. the common uninitialized 'MyObject obj;' bug)
> - To build on the stack, have to use 'scope'
> 
> Good points:
> + No need to type '*' everywhere when you use class objects
> + ??? anything else ???
> 
> 
> I guess I feel like that if D were Java, I'd never see the pointers, "Foo foo;" would always mean a heap-allocated thing, and everything would be cool. But with D sometimes "Foo foo" means a stack allocated thing, and sometimes it doesn't.  I'm starting to think the extra cognitive load isn't really worth it.
> 
> In large part it all stems from the decision to make classes and structs different.  That seems nice in theory, but as time goes on the two are becoming more and more alike.  Classes can now be stack-allocated with scope.  Structs are supposedly going to get constructors, and maybe even destructors.  It kind of makes me think that maybe separating structs and classes was a bad idea.  I have yet to ever once say to myself "thank goodness structs and classes are different in D!", though plenty of times I've muttered "dangit why can't I just get a default copy constructor for this class" or "shoot, these static opCalls are annoying" or "dang, I wish I could get a weak reference to a struct", etc.
> 
> --bb

i agree. D's rules for this are more complex than C++'s and their advantage is questionable.
besides, not having to type *'s (everywhere except in uninitialized declarations) is a separate feature. we could have C++-like behaviour and still use the implicit * deduction.
August 15, 2007
Bill Baxter wrote:
> In large part it all stems from the decision to make classes and structs
> different.  That seems nice in theory, but as time goes on the two are
> becoming more and more alike.  Classes can now be stack-allocated with
> scope.  Structs are supposedly going to get constructors, and maybe even
> destructors.  It kind of makes me think that maybe separating structs
> and classes was a bad idea.  I have yet to ever once say to myself
> "thank goodness structs and classes are different in D!", though plenty
> of times I've muttered "dangit why can't I just get a default copy
> constructor for this class" or "shoot, these static opCalls are
> annoying" or "dang, I wish I could get a weak reference to a struct", etc.
> 

I think the separation was a good idea. I like structs not having hidden fields, being laid out in memory exactly as I write the code, and having no performance overhead due to vtables, etc. In C++, the only difference is that structs default to public while classes default to private. Where's the use in that? Just use a class for everything - and most people do. I like my POD datatype, thank you very much.

With that said, I agree that hiding class pointers may not have been a good idea. Still, I can't think of many points which would make it a particularly bad idea.

Defaulting to stack allocation somehow would be better: it's easy to write "auto" instead of "scope" and forget about it. But then, the performance in such cases rarely matters, and when it does, you do notice such things because you're looking for them.

"Myobject obj;" being uninitialized is supposed to be a feature, not a bug, just like "T t;" should be explicitly initialized for every T.

The idea is that if you forget to initialize something you get an easy-to-find error: all chars are initialized to 0xff, so if you're wondering why you're getting running into lots of 0xff in some output, you look for uninitialized chars. Ditto for floating point and NaNs.

Integers don't have an "uninitialized" value so they go to zero. IMHO this should perhaps have been made T.min or T.max instead of zero, as zero is so common an initializer that people forget the reason why variables are initialized by default. Walter said that even he's guilty of sometimes leaving integers uninitialized when they should be initialized to zero, and I do it too, but that doesn't mean that's how it should be done.

Initializers are present to catch errors by making code fail hard (as in the
"Object o;" case) instead of silently (as in if you type "int x;" in C/C++ and
proceed to increment or decrement x).

-- 
Remove ".doesnotlike.spam" from the mail address.
August 15, 2007
Possibly because they are not 'pointers to classes' in a strict sense. They don't necessarily have to be implemented with a pointer (though this will usually be the case), and they don't support many *unsafe* pointer operations, such as initialisation to anything (only to objects or null), or arithmetic.

Bill Baxter Wrote:
> I'm starting to seriously wonder if it was a good idea to hide the pointers to classes.  It seemed kinda neat when I was first using D that I could avoid typing *s all the time.  But as time wears on it's starting to seem more like a liability.
> 
> Bad points:
> - Harder to tell whether you're dealing with a pointer or not
>    (c.f. the common uninitialized 'MyObject obj;' bug)
> - To build on the stack, have to use 'scope'
> 
> Good points:
> + No need to type '*' everywhere when you use class objects
> + ??? anything else ???
> 
> 
> I guess I feel like that if D were Java, I'd never see the pointers, "Foo foo;" would always mean a heap-allocated thing, and everything would be cool. But with D sometimes "Foo foo" means a stack allocated thing, and sometimes it doesn't.  I'm starting to think the extra cognitive load isn't really worth it.
> 
> In large part it all stems from the decision to make classes and structs different.  That seems nice in theory, but as time goes on the two are becoming more and more alike.  Classes can now be stack-allocated with scope.  Structs are supposedly going to get constructors, and maybe even destructors.  It kind of makes me think that maybe separating structs and classes was a bad idea.  I have yet to ever once say to myself "thank goodness structs and classes are different in D!", though plenty of times I've muttered "dangit why can't I just get a default copy constructor for this class" or "shoot, these static opCalls are annoying" or "dang, I wish I could get a weak reference to a struct", etc.
> 
> --bb

August 15, 2007
#1 advantage of making them always by-value: Ridiculously inconsistent use of by-value passing, ref passing and pointer passing.

void foo(Thing a);
void foo(ref Thing a);
void foo(Thing *a);

Wait, that's not an advantage at all, that's C++.

 - Gregor Richards
August 15, 2007
OK, OK, I guess I should respond with an argument from computer science as well :)

In the normal definition of Object Orientation, an object is a means of storing a context in which operations can be performed. The abstraction behind this (yay we're modeling the universe in code but realistically we aren't yay) is irrelevant, as fundamentally OO is just a means of storing and passing contexts. Because this is a context, it makes no sense whatsoever to pass it around with duplication - duplicating contexts is nonsense.

structs are sort of a hack for compatibility and/or optimization. They are not contexts, they are means of creating more complicated values. While a "Point" could be a struct, really being a more complicated value, an "NPC" would always be a class, since it is a context.

The fact that this is inconsistent with C++ is irrelevant: D is more to the spirit of good OO.

 - Gregor Richards
August 15, 2007
Bill Baxter wrote:
> I'm starting to seriously wonder if it was a good idea to hide the pointers to classes.  It seemed kinda neat when I was first using D that I could avoid typing *s all the time.  But as time wears on it's starting to seem more like a liability.
> 
> Bad points:
> - Harder to tell whether you're dealing with a pointer or not
>   (c.f. the common uninitialized 'MyObject obj;' bug)
> - To build on the stack, have to use 'scope'
> 
> Good points:
> + No need to type '*' everywhere when you use class objects
> + ??? anything else ???
> 
> 
> I guess I feel like that if D were Java, I'd never see the pointers, "Foo foo;" would always mean a heap-allocated thing, and everything would be cool. But with D sometimes "Foo foo" means a stack allocated thing, and sometimes it doesn't.  I'm starting to think the extra cognitive load isn't really worth it.
> 
> In large part it all stems from the decision to make classes and structs different.  That seems nice in theory, but as time goes on the two are becoming more and more alike.  Classes can now be stack-allocated with scope.  Structs are supposedly going to get constructors, and maybe even destructors.  It kind of makes me think that maybe separating structs and classes was a bad idea.  I have yet to ever once say to myself "thank goodness structs and classes are different in D!", though plenty of times I've muttered "dangit why can't I just get a default copy constructor for this class" or "shoot, these static opCalls are annoying" or "dang, I wish I could get a weak reference to a struct", etc.
> 
> --bb

How about allowing operator overloads on classes which must be treated as reference types?

ByValue* a;
// can't overload opAdd usefully:
assert(a.opAdd(5) != a + 5);

ByRef b;
// but we can if the pointer is hidden
assert(b.opAdd(5) == a + 5);

  -- Reiner
August 15, 2007
Gregor Richards wrote:
> #1 advantage of making them always by-value: Ridiculously inconsistent use of by-value passing, ref passing and pointer passing.
> 
> void foo(Thing a);
> void foo(ref Thing a);
> void foo(Thing *a);
> 
> Wait, that's not an advantage at all, that's C++.

I don't get your point.  Each of those things has different uses in C++.

// if Thing is small/PoD and you don't want changes to affect caller
void foo(Thing a);

// if Thing is bigger, you want to allow caller-visible changes, and you  require calling with non-null
void foo(ref Thing a);

// same as above, but you want to allow null too
void foo(Thing *a);


The ref-can't-be-null thing may not hold for D, but it's true of C++.

--bb
August 15, 2007
Bill Baxter wrote:
> Gregor Richards wrote:
>> #1 advantage of making them always by-value: Ridiculously inconsistent use of by-value passing, ref passing and pointer passing.
>>
>> void foo(Thing a);
>> void foo(ref Thing a);
>> void foo(Thing *a);
>>
>> Wait, that's not an advantage at all, that's C++.
> 
> I don't get your point.  Each of those things has different uses in C++.
> 
> // if Thing is small/PoD and you don't want changes to affect caller
> void foo(Thing a);
> 
> // if Thing is bigger, you want to allow caller-visible changes, and you  require calling with non-null
> void foo(ref Thing a);
> 
> // same as above, but you want to allow null too
> void foo(Thing *a);
> 
> 
> The ref-can't-be-null thing may not hold for D, but it's true of C++.
> 
> --bb

This just makes writing code more complicated. It's difficult to remember whether some function wants a reference or a pointer, and you have to be careful about how you treat them because they're fundamentally different (see the operator overloading post). The advantage is virtually nil, and it would create this huge complication. That's why it's terrible in C++, and that's why it would be terrible in D.

 - Gregor Richards
August 15, 2007
Gregor Richards wrote:
> Bill Baxter wrote:
>> Gregor Richards wrote:
>>> #1 advantage of making them always by-value: Ridiculously inconsistent use of by-value passing, ref passing and pointer passing.
>>>
>>> void foo(Thing a);
>>> void foo(ref Thing a);
>>> void foo(Thing *a);
>>>
>>> Wait, that's not an advantage at all, that's C++.
>>
>> I don't get your point.  Each of those things has different uses in C++.
>>
>> // if Thing is small/PoD and you don't want changes to affect caller
>> void foo(Thing a);
>>
>> // if Thing is bigger, you want to allow caller-visible changes, and you  require calling with non-null
>> void foo(ref Thing a);
>>
>> // same as above, but you want to allow null too
>> void foo(Thing *a);
>>
>>
>> The ref-can't-be-null thing may not hold for D, but it's true of C++.
>>
>> --bb
> 
> This just makes writing code more complicated. It's difficult to remember whether some function wants a reference or a pointer, and you have to be careful about how you treat them because they're fundamentally different (see the operator overloading post). The advantage is virtually nil, and it would create this huge complication. That's why it's terrible in C++, and that's why it would be terrible in D.

We have the same problem in D with value types like 'int'.

Pass by reference has always bothered me.  It hides what's going on at the call site, eg.

int a;
foo(a);
bar(a);

which one modifies a?

Then there is the fact that you cannot pass null, meaning in some cases creating and passing a dummy parameter for an 'out' which you don't actually want.

I actually quite like pointers myself but I like D's arrays more! They're passed by value or by reference and you can always pass null.

If only classes could work in the same way!

Regan
« First   ‹ Prev
1 2 3 4 5 6 7 8 9