www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Newbie comments about D

reply Kristian <kjkilpi gmail.com> writes:
I just discovered this very promising language, and decided to write som=
e  =

comments about it. This post is lenghtly, so sorry about it. And it's ve=
ry  =

possible that issues discussed below are already handled many times over=
  =

(sorry again, if that's the case). (But hey, you can think me as a fresh=
  =

'test subject' ;) ...)

I have been programming with C++ mainly. (I know a lot of other language=
s  =

as well, though.) Issues that I disliked (or that were problematic) in  =

C++ seem to be 'fixed' in D (well, almost all of them; see below). No mo=
re  =

include files, templates are working fine, compiler generates the  =

documentation, etc... just wonderful. And there are property functions, =
 =

invariants, and so on... :)


I was a little surprised that there are no local class objects (put into=
  =

the stack). For example:

struct S {...}
class C {...}

void f() {
     S s;  //s is a local variable
     C c;  //c is NULL, not an object
}

That's not a problem of course. However, it's a bit laborious to write "=
C  =

c =3D new C;" all the time you need a (local) object. And it's inconsist=
ent  =

with other variable declarations.


--- 1 ---

Well, how about this:

The compiler could initialize a variable with a new object or NULL  =

depending on if a value is assigned to it before it's used. For example:=


void f() {
     C c1;  //c1 =3D new C;
     C c2;  //c2 =3D NULL;

     if(c1.f() =3D=3D 1) {...}

     c2 =3D getSomeObject();
}

This unifies all the variable declarations, and you don't need to write =
 =

long " =3D new ..." initializations!

This also means, of course, that an object is always initialized for you=
  =

(as it should, you have provided a constructor for it, haven't you?). Th=
e  =

compiler just optimized it's initial value, i.e. a new object is not  =

allocated when it's unnecessary.


--- 2 ---

One thing I hate in C++ is that you cannot reimplement a member function=
  =

derived from the base class so that other overload functions won't  =

'disappear'. I think this is a well known, and hated, problem in C++. Fo=
r  =

example:

class A {
public:
     virtual void f();
     virtual void f(int);
     virtual void f(float);
};

class B : public A {
public:
     virtual void f();
     //'f(int)' disappears
     //'f(float)' disappears
};

I have never came across to a situation where the other overloads should=
  =

disappear from a deriving class. And, if they should disappear, the  =

programmer can still call them via the base class (i.e. "B b;  =

b.A::f(10);").

Of course, in D you can use an alias to fix this problem, i.e.:

class B : A {
     void f() {...};
     alias A.f f;
}

But this should not be necessary, IMHO. I would hate to write the aliase=
s  =

over and over again...


--- 3 ---

The same goes for the constructors. For example:

class A {
     this() {...}
     this(int) {...}
     this(float) {...}
}

class B : A {
     //all the constructors disappear!
}

This causes a lot of work when you only need to, for example, override o=
ne  =

little tiny function of the base class.


--- 4 ---

By the way, the 'auto' attribute is used with local variables, so would =
a  =

word 'local' be a more logical choice?

void f() {
     local C c =3D new C;
     ...
}


--- 5 ---

Hmm, could it be possible to automatically add auto/local attribute to  =

objects that are not returned (by a function) and that are not assigned =
to  =

anything? For example:

class File {...}  //the file is closed in the destructor

void f() {
     File f =3D new File;  //auto File f =3D new File;

     f.open("myfile.txt");
     f.doSomething();
}

Also, auto/local objects could remain in the stack instead of the heap  =

(but that's only an issue of optimization).


...

That's all folks, keep up the good work! :)
Aug 17 2006
next sibling parent reply Reiner Pope <reiner.pope REMOVE.THIS.gmail.com> writes:
Kristian wrote:
 
 --- 1 ---
 
 Well, how about this:
 
 The compiler could initialize a variable with a new object or NULL 
 depending on if a value is assigned to it before it's used. For example:
 
 void f() {
     C c1;  //c1 = new C;
     C c2;  //c2 = NULL;
 
     if(c1.f() == 1) {...}
 
     c2 = getSomeObject();
 }
 
 This unifies all the variable declarations, and you don't need to write 
 long " = new ..." initializations!
 
 This also means, of course, that an object is always initialized for you 
 (as it should, you have provided a constructor for it, haven't you?). 
 The compiler just optimized it's initial value, i.e. a new object is not 
 allocated when it's unnecessary.
The problem is that the compiler can't tell. While it's possible in trivial cases, one can write arbitrarily complex code, which means the compiler needs to be sufficiently smart to be sure. Walter has referred to this problem before with initialization, and the fact that it is annoying when the compiler is stupid and gets it wrong.
 
 
 --- 4 ---
 
 By the way, the 'auto' attribute is used with local variables, so would 
 a word 'local' be a more logical choice?
 
 void f() {
     local C c = new C;
     ...
 }
A huge change of code would be required for that.
 --- 5 ---
 
 Hmm, could it be possible to automatically add auto/local attribute to 
 objects that are not returned (by a function) and that are not assigned 
 to anything? For example:
 
 class File {...}  //the file is closed in the destructor
 
 void f() {
     File f = new File;  //auto File f = new File;
 
     f.open("myfile.txt");
     f.doSomething();
 }
There's nothing in the spec that prohibits the compiler doing that right now. /Enforcing/ it in the spec could be interesting, though. I still think it is safer to annotate it properly, though. Otherwise you may get into problems where someone else uses that code you showed, and accidentally returns it to something else. Then its behaviour would suddenly change and it wouldn't be destroyed.
 
 Also, auto/local objects could remain in the stack instead of the heap 
 (but that's only an issue of optimization).
Again, no prohibition. Walter has even mentioned that as a future improvement.
Aug 17 2006
next sibling parent reply Chad J <gamerChad _spamIsBad_gmail.com> writes:
Reiner Pope wrote:
 Kristian wrote:
 
 --- 4 ---

 By the way, the 'auto' attribute is used with local variables, so 
 would a word 'local' be a more logical choice?

 void f() {
     local C c = new C;
     ...
 }
A huge change of code would be required for that.
Argh. Can't we rig the compiler to automatically change code over to the new keyword or something? Or at least give good error messages when the obsolete meaning of auto is used, to help coders with the search and replace? Using a new keyword would make something like auto C c; into error causing code at the very least, even if the error message isn't entirely descriptive (we can at least get line number right?). Also I'd suggest using 'scope' instead of 'local', as suggested before. Scope is already a reserved keyword (Kristian look it up in the spec under "Statements", it's quite handy). It also just so happens that the meaning of scope in this context and it's current context is very similar. So no need to rename identifiers that already use the word (because there are none) AND it makes sense, yay. Anyhow, that's my argument for doing it anyways. I'd like to see this done. It also looks like a good pre-1.0 change since it breaks backwards compatibility. Unless there's something I'm missing, it actually doesn't look too difficult to update code if this were done. I'd even be willing to update peoples' code if it makes this happen.
Aug 17 2006
parent reply kris <foo bar.com> writes:
Chad J wrote:
[snip]
 Also I'd suggest using 'scope' instead of 'local', as suggested before. 
 Scope is already a reserved keyword (Kristian look it up in the spec 
 under "Statements", it's quite handy).  It also just so happens that the 
 meaning of scope in this context and it's current context is very 
 similar.  So no need to rename identifiers that already use the word 
 (because there are none) AND it makes sense, yay.
Aye. This seems like a no-brainer? Not sure what technical concerns there might be that are currently stopping this from happening, but it would surely be appropriate to change the usage/keyword before 1.0?
Aug 17 2006
parent Kristian <kjkilpi gmail.com> writes:
On Fri, 18 Aug 2006 02:06:55 +0300, kris <foo bar.com> wrote:

 Chad J wrote:
 [snip]
 Also I'd suggest using 'scope' instead of 'local', as suggested before.  
 Scope is already a reserved keyword (Kristian look it up in the spec  
 under "Statements", it's quite handy).  It also just so happens that  
 the meaning of scope in this context and it's current context is very  
 similar.  So no need to rename identifiers that already use the word  
 (because there are none) AND it makes sense, yay.
Aye. This seems like a no-brainer? Not sure what technical concerns there might be that are currently stopping this from happening, but it would surely be appropriate to change the usage/keyword before 1.0?
Thanks Chad, the scope statement is one very nice feature indeed! :) I think I could also live with the "scope" word (even if there is a bit nicer ring in "local" ;) ). As I mentioned my other post, changes from "auto" to "local"/"scope" could be done automatically (well, I think at least almost all of them anyway), if you need to update old code.
Aug 18 2006
prev sibling parent Kristian <kjkilpi gmail.com> writes:
On Fri, 18 Aug 2006 00:24:44 +0300, Reiner Pope  =

<reiner.pope REMOVE.THIS.gmail.com> wrote:
 Kristian wrote:
  --- 1 ---
  Well, how about this:
  The compiler could initialize a variable with a new object or NULL  =
 depending on if a value is assigned to it before it's used. For examp=
le:
  void f() {
     C c1;  //c1 =3D new C;
     C c2;  //c2 =3D NULL;
      if(c1.f() =3D=3D 1) {...}
      c2 =3D getSomeObject();
 }
  This unifies all the variable declarations, and you don't need to  =
 write long " =3D new ..." initializations!
  This also means, of course, that an object is always initialized for=
=
 you (as it should, you have provided a constructor for it, haven't  =
 you?). The compiler just optimized it's initial value, i.e. a new  =
 object is not allocated when it's unnecessary.
The problem is that the compiler can't tell. While it's possible in =
 trivial cases, one can write arbitrarily complex code, which means the=
=
 compiler needs to be sufficiently smart to be sure. Walter has referre=
d =
 to this problem before with initialization, and the fact that it is  =
 annoying when the compiler is stupid and gets it wrong.
Ok, I hear you. I'm accustomed to my C++ compiler saying "warning: local= = variable X used without having been initialized". Maybe the compiler = misses some bizarre cases. Hey, lets hope that dmd/dmc will also use suc= h = warnings some day... ;) However, if the compiler is unsure which init value it should use, then = a = new object should been used. It should be easy to make a compiler smart = = enough that it gets almost all the cases right. If you write some extrem= e = code, or the code is very time critical (and you're unsure how well the = = compiler will do), then you can define that the object must be initializ= ed = with NULL (e.g. "C c =3D NULL;"). The language should be constructed for common cases, not for some possib= le = situations that happen rariry. Those rare cases can be more or less = awkward to write.
   --- 4 ---
  By the way, the 'auto' attribute is used with local variables, so  =
 would a word 'local' be a more logical choice?
  void f() {
     local C c =3D new C;
     ...
 }
A huge change of code would be required for that.
For greater (and future) good perhaps...? ;) Well, such changes can be done automatically, can't they? (Well, at leas= t = I have such a search & replace program (developed by me).) One solution could be that there would be two different words for the sa= me = attribute (auto & local/scope). Of course, that's not an optimal solutio= n, = but eventually "auto" would wither away (and new people won't even know = = "auto").
Aug 18 2006
prev sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Kristian" <kjkilpi gmail.com> wrote in message 
news:op.tefyzndb5xlco7 mist...

(sorry, my newsreader is, for some reason, not quoting your message [and 
your message alone] properly..)

-----------BEGINQUOTE------------------------
--- 5 ---

Hmm, could it be possible to automatically add auto/local attribute to
objects that are not returned (by a function) and that are not assigned to
anything? For example:

class File {...}  //the file is closed in the destructor

void f() {
     File f = new File;  //auto File f = new File;

     f.open("myfile.txt");
     f.doSomething();
}

-----------ENDQUOTE------------------------

What if you did something like this:

void f()
{
    File f = new File("foo.txt");
    aFunctionThatStoresTheFileHandleElsewhere(f);
}

With the current semantics of RAII class references, this is perfectly 
legal, and would cause a terrible bug whereby 'f' would be destroyed at the 
end of the function and would no longer be a valid reference "elsewhere."

It's certainly a very interesting optimization idea, but it would require 
the compiler to know more than it possibly can, or it would require placing 
very stringent restrictions on how RAII (or these "implicit RAII") class 
references could be used. 
Aug 17 2006
next sibling parent reply Oskar Linde <olREM OVEnada.kth.se> writes:
Jarrett Billingsley wrote:

 "Kristian" <kjkilpi gmail.com> wrote in message
 news:op.tefyzndb5xlco7 mist...
 
 (sorry, my newsreader is, for some reason, not quoting your message [and
 your message alone] properly..)
 
 -----------BEGINQUOTE------------------------
 --- 5 ---
 
 Hmm, could it be possible to automatically add auto/local attribute to
 objects that are not returned (by a function) and that are not assigned to
 anything? For example:
 
 class File {...}  //the file is closed in the destructor
 
 void f() {
      File f = new File;  //auto File f = new File;
 
      f.open("myfile.txt");
      f.doSomething();
 }
 
 -----------ENDQUOTE------------------------
 
 What if you did something like this:
 
 void f()
 {
     File f = new File("foo.txt");
     aFunctionThatStoresTheFileHandleElsewhere(f);
 }
 
 With the current semantics of RAII class references, this is perfectly
 legal, and would cause a terrible bug whereby 'f' would be destroyed at
 the end of the function and would no longer be a valid reference
 "elsewhere."
 
 It's certainly a very interesting optimization idea, but it would require
 the compiler to know more than it possibly can, or it would require
 placing very stringent restrictions on how RAII (or these "implicit RAII")
 class references could be used.
This optimization is identical to the escaping delegate problem. With a global escape analysis, the compiler could make a conservative statement finding cases where f was guaranteed not to be stored anywhere. This would also mean that all called class methods need to be analyzed, as one of them also could save away the this-pointer at some place. In the example above, either the File constructor, f.open or f.doSomething could store the reference somewhere. /Oskar
Aug 18 2006
parent reply Kristian <kjkilpi gmail.com> writes:
On Fri, 18 Aug 2006 11:25:53 +0300, Oskar Linde <olREM OVEnada.kth.se>  =

wrote:

 Jarrett Billingsley wrote:

 "Kristian" <kjkilpi gmail.com> wrote in message
 news:op.tefyzndb5xlco7 mist...

 (sorry, my newsreader is, for some reason, not quoting your message [=
and
 your message alone] properly..)

 -----------BEGINQUOTE------------------------
 --- 5 ---

 Hmm, could it be possible to automatically add auto/local attribute t=
o
 objects that are not returned (by a function) and that are not assign=
ed =
 to
 anything? For example:

 class File {...}  //the file is closed in the destructor

 void f() {
      File f =3D new File;  //auto File f =3D new File;

      f.open("myfile.txt");
      f.doSomething();
 }

 -----------ENDQUOTE------------------------

 What if you did something like this:

 void f()
 {
     File f =3D new File("foo.txt");
     aFunctionThatStoresTheFileHandleElsewhere(f);
 }

 With the current semantics of RAII class references, this is perfectl=
y
 legal, and would cause a terrible bug whereby 'f' would be destroyed =
at
 the end of the function and would no longer be a valid reference
 "elsewhere."

 It's certainly a very interesting optimization idea, but it would  =
 require
 the compiler to know more than it possibly can, or it would require
 placing very stringent restrictions on how RAII (or these "implicit  =
 RAII")
 class references could be used.
This optimization is identical to the escaping delegate problem. With =
a
 global escape analysis, the compiler could make a conservative stateme=
nt
 finding cases where f was guaranteed not to be stored anywhere. This  =
 would
 also mean that all called class methods need to be analyzed, as one of=
=
 them
 also could save away the this-pointer at some place.

 In the example above, either the File constructor, f.open or  =
 f.doSomething
 could store the reference somewhere.

 /Oskar
Lets hope there will be a solution for the escaping delegate problem. Well, what if there would be a 'scope destructor' for classes? It gets = called when an object leaves its scope (and before the main destructor, = of = course, if the object is auto). You could use it to free any resources t= he = object has allocated. For example: class File { ~this_scope() {close();} //the scope destructor void close() {...} } File func() { Class File f; f.open("myfile.txt"); f.doSomething(); return f; } Of course, the file will be closed outside 'func()'. For me it's a bit = vague when you would want to use multiple references to the same file, a= nd = when the file can be closed in such cases. Maybe you should always test = if = a file is open before a reference is used. If there were operators for right side assignment and for the return = statement, then you could do the following: class File { ~this_scope() { if(m_is_closed) close(); } //'src.opAssigment_r()' is called when "dst =3D src;" //(The return value and parameters are not important here, of cours= e) void opAssigment_r() { m_is_closed =3D false; } //'obj.opReturn()' is called when "return obj;" void opReturn() { m_is_closed =3D false; } void close() {...} bool m_is_closed =3D true; } Phuuf, I don't know... I was just playing around with some thoughts. ;) By the way, I am a bit disappointed ;) that nobody commented the = "disappearing overloads/constructors" problem I wrote earlier. Nobody sa= id = "don't worry, these issues will be fixed in future"... *grin*
Aug 18 2006
parent reply "John Reimer" <terminal.node gmail.com> writes:
On Fri, 18 Aug 2006 13:06:15 -0700, Kristian <kjkilpi gmail.com> wrote:

 By the way, I am a bit disappointed ;) that nobody commented the  
 "disappearing overloads/constructors" problem I wrote earlier. Nobody  
 said "don't worry, these issues will be fixed in future"... *grin*
That's because Walter has purposefully chosen to model D after C++ in this regard (and in many others). To him, it's a feature. Although, in the past, I know I've complained that having to alias everything forward feels hackish and annoying. Over the last while, I've just learned to live with it. :P -JJR
Aug 18 2006
parent reply Lars Ivar Igesund <larsivar igesund.net> writes:
John Reimer wrote:

 On Fri, 18 Aug 2006 13:06:15 -0700, Kristian <kjkilpi gmail.com> wrote:
 
 By the way, I am a bit disappointed ;) that nobody commented the
 "disappearing overloads/constructors" problem I wrote earlier. Nobody
 said "don't worry, these issues will be fixed in future"... *grin*
That's because Walter has purposefully chosen to model D after C++ in this regard (and in many others). To him, it's a feature. Although, in the past, I know I've complained that having to alias everything forward feels hackish and annoying. Over the last while, I've just learned to live with it. :P -JJR
True, although what Walter have said in the past, is that it is _not_ considered a problem in the C++ world. -- Lars Ivar Igesund blog at http://larsivi.net DSource & #D: larsivi
Aug 18 2006
parent "John Reimer" <terminal.node gmail.com> writes:
On Fri, 18 Aug 2006 14:40:29 -0700, Lars Ivar Igesund  
<larsivar igesund.net> wrote:

 John Reimer wrote:

 On Fri, 18 Aug 2006 13:06:15 -0700, Kristian <kjkilpi gmail.com> wrote:

 By the way, I am a bit disappointed ;) that nobody commented the
 "disappearing overloads/constructors" problem I wrote earlier. Nobody
 said "don't worry, these issues will be fixed in future"... *grin*
That's because Walter has purposefully chosen to model D after C++ in this regard (and in many others). To him, it's a feature. Although, in the past, I know I've complained that having to alias everything forward feels hackish and annoying. Over the last while, I've just learned to live with it. :P -JJR
True, although what Walter have said in the past, is that it is _not_ considered a problem in the C++ world.
Yes, that appears to be true. I'm not knowlegdable enough in that regard to know if being able to do that is a good or bad thing or whether C++ people just accept the way things work because they are used to it. I believe Java works differently in this regard, no? -JJR
Aug 18 2006
prev sibling parent Stewart Gordon <smjg_1998 yahoo.com> writes:
Jarrett Billingsley wrote:
 "Kristian" <kjkilpi gmail.com> wrote in message 
 news:op.tefyzndb5xlco7 mist...
 
 (sorry, my newsreader is, for some reason, not quoting your message [and 
 your message alone] properly..)
<snip> IMX, Outlook Express never quotes properly. But see http://home.in.tum.de/~jain/software/oe-quotefix/ Stewart.
Aug 18 2006