www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - First D project - some observations

reply Mike <Mike_member pathlink.com> writes:
Hi!

I wanted to share some observations of an experienced C++ programmer who has now
spent his first 10-12 hours with D.

First a little history on my project: I'm currently building a small vm (nothing
fancy) for a little hobby project I'm doing. The vm is already running in C++, I
just need to build a little, C-ish script parser around that thing.

Anyway, I have a little declaration problem in C++. It's not the first time I
have exactly this problem, and I solved it numerous times, but I'm getting tired
of it, and more frustrated every time I have something like this.

class Block;

class Instruction
{
..
Block *MyScope;
};

class Block : public Instruction
{
..
List<Instruction> MyInstructions;
List<Symbol> MyLocalSymbols;
Block *MyParent;
};

Instruction needs to call Block to get it's symbols, Block has it's local
symbols and gets undefined symbols from it's parent. If parent is NULL, this is
the global block. Symbols can be variables or (nested) functions. That's the
idea.

But Instruction can't call Block's member functions, because Block is just a

declarations. I stopped coding at that point, since I was frustrated, seeing
myself AGAIN wasting hours with moving code around, inside and outside the class
declaration to get that thing to compile. Ok, I could create a "symboltable"
class and derive "block" from both "instruction" and "symboltable". But why? Why
another class if it's just needed in one place anyhow? And: No wonder C++ needs
multiple inheritance!

So I decided to finally try out D. Downloaded latest versions of akIDE and DMD,
and after about 30-45 minutes converting my ~500 lines C++ code to ~350 lines D
code it ran exactly like before! Nice, I thought. So I've worked on that project
yesterday and today and it went really well, so I feel the urge now to summarize
my impressions so far:

On the plus side:

+ No forward declarations/No header files

I think that's the singlemost important thing to me about D. I hate those
forward declarations, really. I hate them more than header files, which I hate a
great deal, after numerous hours of playing solitaire while recompiling, because
I had to add a new member to a base class.

(And no more #incldue typos! :-)

+ Case "string", == for strings

In that particular case of writing a parser this is a godsend, but I imagine
this will come in handy in other areas as well. No more !strcmp.

+ The ~ operator

Never again this:

char buf[200];
sprintf(buf, "Error in blabla function (dbg: x = %i)", x);
throw new exception(buf);

Nice!

+ No ; after class definition

This feels just natural.

+ this/super

Great! Never again this: Long, descriptive class name with one hard to see typo,
copy paste for three constructors and one descructor, compile, find out you made
a typo. And makes it easier to change a class name, too.

And I found this to be quite natural from the start, I never accidentally wrote
a constructor the C++ way.

+ member initialization with =, rather than with initializer lists

Another great thing, especially for me. I can't remember how many times I
actually tried to initialize members via the D syntax, just to find out - d'oh,
C++ can't do that. Forgot that again! Fits much better into the overall feel of
a C-ish language than those initializer lists.

+ Dynamic Arrays

Yes!

+ Garbage Collection

Yes! Yes! Yes!

On the - side:

- Hard to find odd crashes

I had some trouble, until I figured out that my program seemed to crash/exit
immediatly whenever an exception was not caught. Couldn't the compiler catch
errors like that? That was really annoying. The problems was that I had no idea
about where the crash happened and it took quite some time to find it.

Another thing was that on of my functions (defined as bit) accidentally had one
path out of it without a return statement. Immediate crash when calling that
function, again no error from the compiler. Every C++-compiler (iirc) catched
things like that. These crashes are hard to find, really. Especially when you're
not used to looking for something like THAT.

- .length property can't be lvalue

MyIntArray.length++;

Why not?

- class instantiation is a bit confusing, at least for c++ programmers

I intuitively expect something like

HelloWorldClass writehello;
writehello.doIt();

NOT to crash the program. But, well, that's something I can life with :-)

- no "bool"

Can't there be an "alias bool bit;" built in?

Summary:
--------

I think I will start porting my C++ project over to D, since it's just a hobby
project, so I have time to do that. And D is nearly the language that I wish C++
to be, honestly (add bool and it is :-). The crashes I mentioned make me wonder,
since it wouldn't be too hard to find them at compile time, anyhow, maybe it's
just me, I haven't found the time to play with the compiler settings.

The things I brought up aren't really acedemic, but I like to get dirty while
programming, change my design constantly because I just had that other idea that
I NEED to try out. For that D seems to be just the right language. Very
practical, I like that. Add to that about 7-8 years of frustration with C++
header files, forward declarations, externs, pointers to pointers and stuff, and
I just have to say: D puts the fun back in programming! Thanks!

So, wish you guys a nice day and be sure to watch BSG tonight :-)

-Mike
Feb 10 2006
next sibling parent reply "Derek Parnell" <derek psych.ward> writes:
On Sat, 11 Feb 2006 02:59:24 +1100, Mike <Mike_member pathlink.com> wrote:

 Hi!

 I wanted to share some observations of an experienced C++ programmer who  
 has now
 spent his first 10-12 hours with D.
Welcome! [snip]
 On the - side:

 - Hard to find odd crashes

 I had some trouble, until I figured out that my program seemed to  
 crash/exit
 immediatly whenever an exception was not caught. Couldn't the compiler  
 catch
 errors like that? That was really annoying. The problems was that I had  
 no idea
 about where the crash happened and it took quite some time to find it.
The 'official' response is to use a debugger to locate the line that is crashing. And if you are using a Windows platform you have to use an old unsupported debugger that you can buy from DigitalMars.
 Another thing was that on of my functions (defined as bit) accidentally  
 had one
 path out of it without a return statement. Immediate crash when calling  
 that
 function, again no error from the compiler. Every C++-compiler (iirc)  
 catched
 things like that. These crashes are hard to find, really. Especially  
 when you're
 not used to looking for something like THAT.
Try using the "-w" switch when compiling. I think it warns about these errors.
 - .length property can't be lvalue

 MyIntArray.length++;

 Why not?
Because .length is not a (pseudo-)field, it is actually a (pseudo-)method. MyIntArray.length++; is equivalent to ... MyIntArray.length()++; which has no effect so is not allowed. MyIntArray.length = MyIntArray.length + 1; is equivalent to ... MyIntArray.length(MyIntArray.length() + 1);
 - class instantiation is a bit confusing, at least for c++ programmers

 I intuitively expect something like

 HelloWorldClass writehello;
 writehello.doIt();

 NOT to crash the program. But, well, that's something I can life with :-)
Yes, this is definitely a D thing. The rationale (I think) is that because class instances live on the heap, they must be explicitly constructed.
 - no "bool"

 Can't there be an "alias bool bit;" built in?
Yes there is. I use it all the time. What happens when you try this ... import std.stdio; void main() { bool foo = 1; writefln(foo); } -- Derek Parnell Melbourne, Australia
Feb 10 2006
parent reply "Søren J. Løvborg" <web kwi.dk> writes:
Mike <Mike_member pathlink.com> wrote:
 - .length property can't be lvalue
 MyIntArray.length++;

 Why not?
"Derek Parnell" <derek psych.ward> wrote:
 Because .length is not a (pseudo-)field, it is actually a (pseudo-)method.

  MyIntArray.length++;

 is equivalent to ...

   MyIntArray.length()++;

 which has no effect so is not allowed.
That really shouldn't matter. MyIntArray.length() = 5; is obviously not right, but that doesn't prevent MyIntArray.length = 5; from being the way to do it. Anywhere a = a + 1 works, a += 1 and a++ should work (or ++a, I guess), since they're semantically equivalent. Søren J. Løvborg web kwi.dk
Feb 11 2006
next sibling parent "Derek Parnell" <derek psych.ward> writes:
On Sun, 12 Feb 2006 07:43:45 +1100, Søren J. Løvborg <web kwi.dk> wrote:

 Mike <Mike_member pathlink.com> wrote:
 - .length property can't be lvalue
 MyIntArray.length++;

 Why not?
"Derek Parnell" <derek psych.ward> wrote:
 Because .length is not a (pseudo-)field, it is actually a  
 (pseudo-)method.

  MyIntArray.length++;

 is equivalent to ...

   MyIntArray.length()++;

 which has no effect so is not allowed.
That really shouldn't matter. MyIntArray.length() = 5; is obviously not right, but that doesn't prevent MyIntArray.length = 5; from being the way to do it. Anywhere a = a + 1 works, a += 1 and a++ should work (or ++a, I guess), since they're semantically equivalent.
I agree with you that it shouldn't matter, but it does and all I did was to explain why. Look at the D 'property' functionality. Its the same deal there. class Foo { void Bar(int) { . . . } int Bar() { . . . } } Foo a = new Foo; a.Bar = 1; // calls a.Bar(1); x = a.Bar; // calls a.Bar(); You can't do a.Bar++ either because it sees this as a.Bar()++. You have to do a.Bar = a.Bar + 1; which it sees as a.Bar(a.Bar() + 1); I hope that one day the compiler can be made sophisticated enough to pick up on this anomaly. -- Derek Parnell Melbourne, Australia
Feb 11 2006
prev sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Søren J. Løvborg" <web kwi.dk> wrote in message 
news:dsli97$2osl$1 digitaldaemon.com...
 Anywhere a = a + 1 works, a += 1 and a++ should work (or ++a, I guess), 
 since they're semantically equivalent.
Not quite. In a = a + 1, "a" is evaluated twice. In a += 1, "a" is evaluated only once. The problem is that with basic types, like int, it's easy to determine where to get the value and where to put it back; it's just a memory location. But you can't do the same with properties; there are separate "get" and "set" functions, which the compiler has to figure out, and it may not be possible for the compiler to determine the matching "set" for a "get" or vice versa. class A { private int mSomeProp; public int someProp { get { return mSomeProp; } set(int value) { return mSomeProp = value; } } } finding the corresponding get/set would be trivial, and A a = new A(); a.someProp += 5; Would be really easy to do. But Walter doesn't like this syntax. I forget what his argument is. It was something flimsy, IIRC.
Feb 11 2006
prev sibling next sibling parent Nick <Nick_member pathlink.com> writes:
Hi and welcome to the world of D! We're always glad to see someone's fresh
opinions of the language, especially when they are so positive as yours :-)
Below I have a few comments to some of your points:

+ No forward declarations/No header files
Forward declarations - wow, I had actually forgotten about those. Whenever I go back to coding C++ (mostly on other people's projects at my uni), I always discover a bunch of things about the language I have quite simply forgotten, and I used to be quite fluent.
(And no more #incldue typos! :-)
But you get the "improt" ones instead ;-)
+ Case "string", == for strings
Another mistake I keep doing in C++ now.
Another thing was that on of my functions (defined as bit) accidentally had one
path out of it without a return statement. Immediate crash when calling that
function, again no error from the compiler. Every C++-compiler (iirc) catched
things like that. These crashes are hard to find, really. Especially when
you're not used to looking for something like THAT.
We've had looong discussions about this one. As it is now, DMD basically inserts an assert(0); at the end of every non-void function. But the error messages have line numbers, so they shouldn't really be that hard to find? There are some cases in which every path ends up with a return statement, but none of the paths run to the end of the function (ie. in a switch statement), and in those cases it is damn near impossible for the compiler to know whether or not there should be a return at the end. It might depend on parameter values, etc. I basically see the "assert(0)" as a If-my-algorithm-is-correct-I-should- never-reach-this-point check.
MyIntArray.length++;

Why not?
Seconded.
HelloWorldClass writehello;
writehello.doIt();
Since there is a fundamental difference between how C++ and D handles the problem (writehello is just a reference in D, not the object instance itself), it would cause MORE confusion if the syntax was kept, since C++ programmers would also expect it to _mean_ the same if it looks the same.
- no "bool"

Can't there be an "alias bool bit;" built in?
There is ;-) Nick
Feb 10 2006
prev sibling next sibling parent Hasan Aljudy <hasan.aljudy gmail.com> writes:
The same reasons I came to D :) except I don't have that long of an 
experience with C++

recently I had to come back to c++ for university assignments .. and man 
.. C++ really really sucks!!!!!!!!!!!

I wish there was a D -> C++ convertor, so I can write my assignments in 
D then convert them to C++ :D

Mike wrote:
 Hi!
 
 I wanted to share some observations of an experienced C++ programmer who has
now
 spent his first 10-12 hours with D.
 
 First a little history on my project: I'm currently building a small vm
(nothing
 fancy) for a little hobby project I'm doing. The vm is already running in C++,
I
 just need to build a little, C-ish script parser around that thing.
 
 Anyway, I have a little declaration problem in C++. It's not the first time I
 have exactly this problem, and I solved it numerous times, but I'm getting
tired
 of it, and more frustrated every time I have something like this.
 
 class Block;
 
 class Instruction
 {
 ..
 Block *MyScope;
 };
 
 class Block : public Instruction
 {
 ..
 List<Instruction> MyInstructions;
 List<Symbol> MyLocalSymbols;
 Block *MyParent;
 };
 
 Instruction needs to call Block to get it's symbols, Block has it's local
 symbols and gets undefined symbols from it's parent. If parent is NULL, this is
 the global block. Symbols can be variables or (nested) functions. That's the
 idea.
 
 But Instruction can't call Block's member functions, because Block is just a

 declarations. I stopped coding at that point, since I was frustrated, seeing
 myself AGAIN wasting hours with moving code around, inside and outside the
class
 declaration to get that thing to compile. Ok, I could create a "symboltable"
 class and derive "block" from both "instruction" and "symboltable". But why?
Why
 another class if it's just needed in one place anyhow? And: No wonder C++ needs
 multiple inheritance!
 
 So I decided to finally try out D. Downloaded latest versions of akIDE and DMD,
 and after about 30-45 minutes converting my ~500 lines C++ code to ~350 lines D
 code it ran exactly like before! Nice, I thought. So I've worked on that
project
 yesterday and today and it went really well, so I feel the urge now to
summarize
 my impressions so far:
 
 On the plus side:
 
 + No forward declarations/No header files
 
 I think that's the singlemost important thing to me about D. I hate those
 forward declarations, really. I hate them more than header files, which I hate
a
 great deal, after numerous hours of playing solitaire while recompiling,
because
 I had to add a new member to a base class.
 
 (And no more #incldue typos! :-)
 
 + Case "string", == for strings
 
 In that particular case of writing a parser this is a godsend, but I imagine
 this will come in handy in other areas as well. No more !strcmp.
 
 + The ~ operator
 
 Never again this:
 
 char buf[200];
 sprintf(buf, "Error in blabla function (dbg: x = %i)", x);
 throw new exception(buf);
 
 Nice!
 
 + No ; after class definition
 
 This feels just natural.
 
 + this/super
 
 Great! Never again this: Long, descriptive class name with one hard to see
typo,
 copy paste for three constructors and one descructor, compile, find out you
made
 a typo. And makes it easier to change a class name, too.
 
 And I found this to be quite natural from the start, I never accidentally wrote
 a constructor the C++ way.
 
 + member initialization with =, rather than with initializer lists
 
 Another great thing, especially for me. I can't remember how many times I
 actually tried to initialize members via the D syntax, just to find out - d'oh,
 C++ can't do that. Forgot that again! Fits much better into the overall feel of
 a C-ish language than those initializer lists.
 
 + Dynamic Arrays
 
 Yes!
 
 + Garbage Collection
 
 Yes! Yes! Yes!
 
 On the - side:
 
 - Hard to find odd crashes
 
 I had some trouble, until I figured out that my program seemed to crash/exit
 immediatly whenever an exception was not caught. Couldn't the compiler catch
 errors like that? That was really annoying. The problems was that I had no idea
 about where the crash happened and it took quite some time to find it.
 
 Another thing was that on of my functions (defined as bit) accidentally had one
 path out of it without a return statement. Immediate crash when calling that
 function, again no error from the compiler. Every C++-compiler (iirc) catched
 things like that. These crashes are hard to find, really. Especially when
you're
 not used to looking for something like THAT.
 
 - .length property can't be lvalue
 
 MyIntArray.length++;
 
 Why not?
 
 - class instantiation is a bit confusing, at least for c++ programmers
 
 I intuitively expect something like
 
 HelloWorldClass writehello;
 writehello.doIt();
 
 NOT to crash the program. But, well, that's something I can life with :-)
 
 - no "bool"
 
 Can't there be an "alias bool bit;" built in?
 
 Summary:
 --------
 
 I think I will start porting my C++ project over to D, since it's just a hobby
 project, so I have time to do that. And D is nearly the language that I wish
C++
 to be, honestly (add bool and it is :-). The crashes I mentioned make me
wonder,
 since it wouldn't be too hard to find them at compile time, anyhow, maybe it's
 just me, I haven't found the time to play with the compiler settings.
 
 The things I brought up aren't really acedemic, but I like to get dirty while
 programming, change my design constantly because I just had that other idea
that
 I NEED to try out. For that D seems to be just the right language. Very
 practical, I like that. Add to that about 7-8 years of frustration with C++
 header files, forward declarations, externs, pointers to pointers and stuff,
and
 I just have to say: D puts the fun back in programming! Thanks!
 
 So, wish you guys a nice day and be sure to watch BSG tonight :-)
 
 -Mike
 
 
Feb 10 2006
prev sibling next sibling parent "Unknown W. Brackets" <unknown simplemachines.org> writes:
That's very strange.  Were you compiling it with -release or something 
silly like that?  In that case, it will immediately crash.  However, 
that is not the recommended way to develop code; instead, simply leave 
it off an asserts (and array bounds checking, etc.) will be enabled.

If you didn't use -release, you should have seen asserts, thrown 
exceptions and other such things.

-[Unknown]

 - Hard to find odd crashes
 
 I had some trouble, until I figured out that my program seemed to crash/exit
 immediatly whenever an exception was not caught. Couldn't the compiler catch
 errors like that? That was really annoying. The problems was that I had no idea
 about where the crash happened and it took quite some time to find it.
 
 Another thing was that on of my functions (defined as bit) accidentally had one
 path out of it without a return statement. Immediate crash when calling that
 function, again no error from the compiler. Every C++-compiler (iirc) catched
 things like that. These crashes are hard to find, really. Especially when
you're
 not used to looking for something like THAT.
Feb 10 2006
prev sibling parent Georg Wrede <georg.wrede nospam.org> writes:
There's nothing as valuable as these first-time experiences with D!!!

We in this newsgroup are just too familiar with all dos don'ts of D, to
ever imagine what it looks like to new people.

Now that we (as always?) are approaching 1.0, stuff like this should be
examined with a _microscope_ to find all the things that put off new users.

For everyone that bothers to write here there has to be a thousand who
get the same feelings, and who broadcast them around in the office, and
over beer.


Mike wrote:
 Hi!
 
 I wanted to share some observations of an experienced C++ programmer
 who has now spent his first 10-12 hours with D.
 
 First a little history on my project: I'm currently building a small
 vm (nothing fancy) for a little hobby project I'm doing. The vm is
 already running in C++, I just need to build a little, C-ish script
 parser around that thing.
 
 Anyway, I have a little declaration problem in C++. It's not the
 first time I have exactly this problem, and I solved it numerous
 times, but I'm getting tired of it, and more frustrated every time I
 have something like this.
 
 class Block;
 
 class Instruction { .. Block *MyScope; };
 
 class Block : public Instruction { .. List<Instruction>
 MyInstructions; List<Symbol> MyLocalSymbols; Block *MyParent; };
 
 Instruction needs to call Block to get it's symbols, Block has it's
 local symbols and gets undefined symbols from it's parent. If parent
 is NULL, this is the global block. Symbols can be variables or
 (nested) functions. That's the idea.
 
 But Instruction can't call Block's member functions, because Block is

 forward declarations. I stopped coding at that point, since I was
 frustrated, seeing myself AGAIN wasting hours with moving code
 around, inside and outside the class declaration to get that thing to
 compile. Ok, I could create a "symboltable" class and derive "block"
 from both "instruction" and "symboltable". But why? Why another class
 if it's just needed in one place anyhow? And: No wonder C++ needs 
 multiple inheritance!
 
 So I decided to finally try out D. Downloaded latest versions of
 akIDE and DMD, and after about 30-45 minutes converting my ~500 lines
 C++ code to ~350 lines D code it ran exactly like before! Nice, I
 thought. So I've worked on that project yesterday and today and it
 went really well, so I feel the urge now to summarize my impressions
 so far:
 
 On the plus side:
 
 + No forward declarations/No header files
 
 I think that's the singlemost important thing to me about D. I hate
 those forward declarations, really. I hate them more than header
 files, which I hate a great deal, after numerous hours of playing
 solitaire while recompiling, because I had to add a new member to a
 base class.
 
 (And no more #incldue typos! :-)
 
 + Case "string", == for strings
 
 In that particular case of writing a parser this is a godsend, but I
 imagine this will come in handy in other areas as well. No more
 !strcmp.
 
 + The ~ operator
 
 Never again this:
 
 char buf[200]; sprintf(buf, "Error in blabla function (dbg: x = %i)",
 x); throw new exception(buf);
 
 Nice!
 
 + No ; after class definition
 
 This feels just natural.
 
 + this/super
 
 Great! Never again this: Long, descriptive class name with one hard
 to see typo, copy paste for three constructors and one descructor,
 compile, find out you made a typo. And makes it easier to change a
 class name, too.
 
 And I found this to be quite natural from the start, I never
 accidentally wrote a constructor the C++ way.
 
 + member initialization with =, rather than with initializer lists
 
 Another great thing, especially for me. I can't remember how many
 times I actually tried to initialize members via the D syntax, just
 to find out - d'oh, C++ can't do that. Forgot that again! Fits much
 better into the overall feel of a C-ish language than those
 initializer lists.
 
 + Dynamic Arrays
 
 Yes!
 
 + Garbage Collection
 
 Yes! Yes! Yes!
 
 On the - side:
 
 - Hard to find odd crashes
 
 I had some trouble, until I figured out that my program seemed to
 crash/exit immediatly whenever an exception was not caught. Couldn't
 the compiler catch errors like that? That was really annoying. The
 problems was that I had no idea about where the crash happened and it
 took quite some time to find it.
 
 Another thing was that on of my functions (defined as bit)
 accidentally had one path out of it without a return statement.
 Immediate crash when calling that function, again no error from the
 compiler. Every C++-compiler (iirc) catched things like that. These
 crashes are hard to find, really. Especially when you're not used to
 looking for something like THAT.
 
 - .length property can't be lvalue
 
 MyIntArray.length++;
 
 Why not?
 
 - class instantiation is a bit confusing, at least for c++
 programmers
 
 I intuitively expect something like
 
 HelloWorldClass writehello; writehello.doIt();
 
 NOT to crash the program. But, well, that's something I can life with
 :-)
 
 - no "bool"
 
 Can't there be an "alias bool bit;" built in?
 
 Summary: --------
 
 I think I will start porting my C++ project over to D, since it's
 just a hobby project, so I have time to do that. And D is nearly the
 language that I wish C++ to be, honestly (add bool and it is :-). The
 crashes I mentioned make me wonder, since it wouldn't be too hard to
 find them at compile time, anyhow, maybe it's just me, I haven't
 found the time to play with the compiler settings.
 
 The things I brought up aren't really acedemic, but I like to get
 dirty while programming, change my design constantly because I just
 had that other idea that I NEED to try out. For that D seems to be
 just the right language. Very practical, I like that. Add to that
 about 7-8 years of frustration with C++ header files, forward
 declarations, externs, pointers to pointers and stuff, and I just
 have to say: D puts the fun back in programming! Thanks!
 
 So, wish you guys a nice day and be sure to watch BSG tonight :-)
 
 -Mike
 
 
Feb 20 2006