www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - operator new(): struct v. class

reply C. Dunn <cdunn2001 gmail.com> writes:
Walter, could you please address this?  I have no problem at all with your
design decisions.  All I want is an operator New() that the compiler will
understand, and which allows me to compare the performance of struct pointers
to classes.

I have outlined the issue below:


Walter Bright Wrote:

 James Dennett wrote:
 Walter Bright wrote:
 Value types are fundamentally different from reference types. D gives
 you the choice.

C++ gives you *more* choice by allowing easier migration between the two without imposing performance or syntactic differences.

That isn't my experience. In my work on DMDscript in D, I changed some types between struct and class to try out some variations, and found it to be a lot easier than in C++. For one thing, I didn't have to find and edit all the -> and .'s.

But Walter, how did you handle operator new()? It needs to be agnostic about class/struct. class C{int x;}; stuct S{int x;}; typedef C MyType; //typedef S* MyType; MyType inst = new MyType; If you use the second typedef, this will not compile! That is the problem. Why not provide an operator New() which expects a pointer type when used for structs? Just have the compiler translate it. I cannot see how to write such a generic operator New() myself. This one small change would be a great boon to any C/C++ programmer thinking of adopting D.
Aug 17 2007
parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
C. Dunn wrote:
 Walter, could you please address this?  I have no problem at all with your
design decisions.  All I want is an operator New() that the compiler will
understand, and which allows me to compare the performance of struct pointers
to classes.
 
 I have outlined the issue below:
 
 
 Walter Bright Wrote:
 
 
James Dennett wrote:

Walter Bright wrote:

Value types are fundamentally different from reference types. D gives
you the choice.

C++ gives you *more* choice by allowing easier migration between the two without imposing performance or syntactic differences.

That isn't my experience. In my work on DMDscript in D, I changed some types between struct and class to try out some variations, and found it to be a lot easier than in C++. For one thing, I didn't have to find and edit all the -> and .'s.

But Walter, how did you handle operator new()? It needs to be agnostic about class/struct. class C{int x;}; stuct S{int x;}; typedef C MyType; //typedef S* MyType; MyType inst = new MyType; If you use the second typedef, this will not compile! That is the problem. Why not provide an operator New() which expects a pointer type when used for structs? Just have the compiler translate it. I cannot see how to write such a generic operator New() myself. This one small change would be a great boon to any C/C++ programmer thinking of adopting D.

It's a trivial bit of template code. Something like this: T New(T)() { static if (is(T U == U*)) { return new U; } else { return new T; } } class C {} struct S {} void main() { C c = New!(C); S* s = New!(S*); } Handling constructor arguments, too, is only a little more complicated. -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Aug 17 2007
parent reply C. Dunn <cdunn2001 gmail.com> writes:
Kirk McDonald Wrote:

 But Walter, how did you handle operator new()?  It needs to be agnostic about
class/struct.
 
 class C{int x;};
 stuct S{int x;};
 typedef C MyType;
 //typedef S* MyType;
 MyType inst = new MyType;
 
 If you use the second typedef, this will not compile!  That is the problem.
 
 Why not provide an operator New() which expects a pointer type when used for
structs?  Just have the compiler translate it.  I cannot see how to write such
a generic operator New() myself.
 

It's a trivial bit of template code. Something like this: T New(T)() { static if (is(T U == U*)) { return new U; } else { return new T; } } class C {} struct S {} void main() { C c = New!(C); S* s = New!(S*); }

I don't understand your static if expression. Where in the docs is there an explanation for "is(T U == U*)"? I completely missed that, and I really do not understand what it does.
 
 Handling constructor arguments, too, is only a little more complicated.

Someone who can figure it out does not need to. I think that's why people are ignoring my concern. It's disregard for the novice. If y'all want C++ programmers to adopt D, you have to make it easy. C++ is entrenched. This operator new() issue and the lack of a stack trace from an exception thrown during contract-checking weaken the arguments for adoption. Maybe someday these will be addressed. D certainly has potential. And yes, before anybody mentions it, flectioned is really cool. If it gets integrated into tango, and if tango is released for D 2.0, then the stack-trace issue might disappear. Then maybe tango will provide an operator New().
Aug 20 2007
parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
C. Dunn wrote:
 Kirk McDonald Wrote:
 
 
But Walter, how did you handle operator new()?  It needs to be agnostic about
class/struct.

class C{int x;};
stuct S{int x;};
typedef C MyType;
//typedef S* MyType;
MyType inst = new MyType;

If you use the second typedef, this will not compile!  That is the problem.

Why not provide an operator New() which expects a pointer type when used for
structs?  Just have the compiler translate it.  I cannot see how to write such
a generic operator New() myself.

It's a trivial bit of template code. Something like this: T New(T)() { static if (is(T U == U*)) { return new U; } else { return new T; } } class C {} struct S {} void main() { C c = New!(C); S* s = New!(S*); }

I don't understand your static if expression. Where in the docs is there an explanation for "is(T U == U*)"? I completely missed that, and I really do not understand what it does.

It's the IsExpression: http://www.digitalmars.com/d/expression.html#IsExpression Specifically, it's this form of the IsExpression: is ( Type Identifier == TypeSpecialization ) "The condition is satisfied if Type is semantically correct and is the same as TypeSpecialization. The Identifier is declared to be either an alias of the TypeSpecialization or, if TypeSpecialization is dependent on Identifier, the deduced type." That is, if T can be expressed as U*, is() evaluates to true, and U is declared to be an alias to the appropriate type.
 
Handling constructor arguments, too, is only a little more complicated.

Someone who can figure it out does not need to.

I don't understand what you mean by this.
 I think that's why people are ignoring my concern.  It's disregard for the
novice.
 
 If y'all want C++ programmers to adopt D, you have to make it easy.  C++ is
entrenched.  This operator new() issue and the lack of a stack trace from an
exception thrown during contract-checking weaken the arguments for adoption. 
Maybe someday these will be addressed.  D certainly has potential.
 
 And yes, before anybody mentions it, flectioned is really cool.  If it gets
integrated into tango, and if tango is released for D 2.0, then the stack-trace
issue might disappear.  Then maybe tango will provide an operator New().

The above is quite easy... assuming you know about the appropriate tools. The IsExpression is one of D's most powerful compile-time tools. If you're doing any generic programming in D, it is one of the first things you should learn about. -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Aug 20 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Kirk McDonald wrote:
 C. Dunn wrote:
 Kirk McDonald Wrote:


 But Walter, how did you handle operator new()?  It needs to be 
 agnostic about class/struct.

 class C{int x;};
 stuct S{int x;};
 typedef C MyType;
 //typedef S* MyType;
 MyType inst = new MyType;

 If you use the second typedef, this will not compile!  That is the 
 problem.

 Why not provide an operator New() which expects a pointer type when 
 used for structs?  Just have the compiler translate it.  I cannot 
 see how to write such a generic operator New() myself.

It's a trivial bit of template code. Something like this: T New(T)() { static if (is(T U == U*)) { return new U; } else { return new T; } } class C {} struct S {} void main() { C c = New!(C); S* s = New!(S*); }

I don't understand your static if expression. Where in the docs is there an explanation for "is(T U == U*)"? I completely missed that, and I really do not understand what it does.

It's the IsExpression: http://www.digitalmars.com/d/expression.html#IsExpression Specifically, it's this form of the IsExpression: is ( Type Identifier == TypeSpecialization ) "The condition is satisfied if Type is semantically correct and is the same as TypeSpecialization. The Identifier is declared to be either an alias of the TypeSpecialization or, if TypeSpecialization is dependent on Identifier, the deduced type." That is, if T can be expressed as U*, is() evaluates to true, and U is declared to be an alias to the appropriate type.

Which I think is a top contender in the running for the weirdest syntax ever devised for a construct in a C-derived language. It's basically an is(Type==TypeSpecialization) that includes type deduction. You're not comparing Identifier with TypeSpecialization so it's bizarre to write anything that looks like U==U*. Obviously U is not U* for any value of U. Any of the following would look more sensible if you ask me: either put the Identifier first is(U : Type == U*) is(U ; Type == U*) is(U | Type == U*) is(U <- Type == U*) or put it last is(Type == U* U) is(Type == U* : U) is(Type == U* | U) is(Type == U* -> U) is(Type == U* with U) or use template syntax is!(U)(Type==U*) And why do we even need is() to do basic type comparisons anyway? What's ambiguous about static if( MyType == OtherType ) { ... } ? I guess you could define a static opEquals, but A) that's useless enough that it could be outlawed B) it wouldn't take a type as an argument so it still wouldn't be ambiguous. --bb
Aug 20 2007
parent reply Kirk McDonald <kirklin.mcdonald gmail.com> writes:
Bill Baxter wrote:
 And why do we even need is() to do basic type comparisons anyway?
 What's ambiguous about
    static if( MyType == OtherType ) {
         ...
    }
 ?
 I guess you could define a static opEquals, but A) that's useless enough 
 that it could be outlawed B) it wouldn't take a type as an argument so 
 it still wouldn't be ambiguous.
 
 --bb

It is ambiguous. Both sides of a comparison must be an expression, and types are not expressions. Allowing that would mean you couldn't determine whether 'MyType' is an expression or a type until after the syntactic pass. This would break some cardinal rules about the ease with which you can parse D code. -- Kirk McDonald http://kirkmcdonald.blogspot.com Pyd: Connecting D and Python http://pyd.dsource.org
Aug 20 2007
next sibling parent BCS <ao pathlink.com> writes:
Reply to Kirk,

 Bill Baxter wrote:
 
 And why do we even need is() to do basic type comparisons anyway?
 What's ambiguous about
 static if( MyType == OtherType ) {
 ...
 }
 ?
 I guess you could define a static opEquals, but A) that's useless
 enough
 that it could be outlawed B) it wouldn't take a type as an argument
 so
 it still wouldn't be ambiguous.
 --bb
 

types are not expressions. Allowing that would mean you couldn't determine whether 'MyType' is an expression or a type until after the syntactic pass. This would break some cardinal rules about the ease with which you can parse D code.

Would it? The syntax could be defined as: CompExp ::= TypeOrExp '==' TypeOrExp; and then wait for the semantic pass to check what is actually used.
Aug 20 2007
prev sibling parent reply Don Clugston <dac nospam.com.au> writes:
Kirk McDonald wrote:
 Bill Baxter wrote:
 And why do we even need is() to do basic type comparisons anyway?
 What's ambiguous about
    static if( MyType == OtherType ) {
         ...
    }
 ?
 I guess you could define a static opEquals, but A) that's useless 
 enough that it could be outlawed B) it wouldn't take a type as an 
 argument so it still wouldn't be ambiguous.

 --bb

It is ambiguous. Both sides of a comparison must be an expression, and types are not expressions. Allowing that would mean you couldn't determine whether 'MyType' is an expression or a type until after the syntactic pass. This would break some cardinal rules about the ease with which you can parse D code.

Ideally, I think, we'd have a merge between is() and typeof()/typeid() static if (typeid(MyType)==typeid(OtherType)) { } There are quite a few cases where we have syntax which is completely different at run-time compared to compile compile-time, yet which do exactly the same thing. __traits and typeinfo seem to be awfully similar, for example. If they were unified, CTFE could grab even more territory from templates.
Sep 04 2007
parent Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= <jmjmak utu.fi.invalid> writes:
Don Clugston wrote:

 Kirk McDonald wrote:
 Bill Baxter wrote:
 And why do we even need is() to do basic type comparisons anyway?
 What's ambiguous about
    static if( MyType == OtherType ) {
         ...
    }
 ?
 I guess you could define a static opEquals, but A) that's useless
 enough that it could be outlawed B) it wouldn't take a type as an
 argument so it still wouldn't be ambiguous.

 --bb

It is ambiguous. Both sides of a comparison must be an expression, and types are not expressions. Allowing that would mean you couldn't determine whether 'MyType' is an expression or a type until after the syntactic pass. This would break some cardinal rules about the ease with which you can parse D code.


Even now you can't tell whether e.g. 'a = b' is syntactically correct without several passes of semantic analysis: template z(string x, string y){mixin(`mixin("template c(string T){mixin(\"alias \"~T~\" t;\");}");c!("int").t `~x~`; int s( string a) { return a.length ? 1 + s(a[1..$]) : 0; } auto ` ~y~`= s(x~y);`);}mixin z!("a","b"); void main() { a = b; }
 
 Ideally, I think, we'd have a merge between is() and typeof()/typeid()
 static if (typeid(MyType)==typeid(OtherType)) {
 }

I find the idea of comparing types directly more natural. Compile time metaobjects feel really intriguing in general. However, I feel sorry for Walter. Implementing all this some day must be tiresome :)
 There are quite a few cases where we have syntax which is completely
 different at run-time compared to compile compile-time, yet which do
 exactly the same thing. __traits and typeinfo seem to be awfully similar,
 for example.

If one the main design principles of D was the principle of least surprise, is expression would have been buried long time ago. Honestly, it has one of the weirdest syntax and semantics.
 If they were unified, CTFE could grab even more territory 
 from templates.

As long as CTFE and/or string mixins can't handle alias parameters there will be need for templates (and/or macros).
Sep 07 2007