www.digitalmars.com         C & C++   DMDScript  

D - Bug: constructor calls

reply Hauke Duden <H.NS.Duden gmx.net> writes:
This works:

class Foo1
{
   this(bool b)
   {
     if(b)
       val=14;
   }
		
   this()
   {
     val=7;
   }
	
protected:
   int val;
}


This doesn't (Error: one path skips constructor:


class Foo2
{
   this(bool b)
   {
     if(b)
       val=14;
     else
       this();	//<< crucial line
   }
		
   this()
   {
     val=7;
   }
	
protected:
   int val;
}


Why is the constructor in Foo1 acceptable, while the one in Foo2 is not? 
I believe this is a bug.

Hauke
Jan 06 2004
next sibling parent reply "Walter" <walter digitalmars.com> writes:
"Hauke Duden" <H.NS.Duden gmx.net> wrote in message
news:btf4jn$1irs$1 digitaldaemon.com...
 This works:

 class Foo1
 {
    this(bool b)
    {
      if(b)
        val=14;
    }

    this()
    {
      val=7;
    }

 protected:
    int val;
 }


 This doesn't (Error: one path skips constructor:


 class Foo2
 {
    this(bool b)
    {
      if(b)
        val=14;
      else
        this(); //<< crucial line
    }

    this()
    {
      val=7;
    }

 protected:
    int val;
 }


 Why is the constructor in Foo1 acceptable, while the one in Foo2 is not?
 I believe this is a bug.
Actually, it is designed to work that way. The semantic phase does a rather primitive data flow analysis to determine that if another constructor is called on one path through the constructor, it must be called on all paths through.
Jan 10 2004
parent reply Hauke Duden <H.NS.Duden gmx.net> writes:
Walter wrote:
 "Hauke Duden" <H.NS.Duden gmx.net> wrote in message
 news:btf4jn$1irs$1 digitaldaemon.com...
 
This works:

class Foo1
{
   this(bool b)
   {
     if(b)
       val=14;
   }

   this()
   {
     val=7;
   }

protected:
   int val;
}


This doesn't (Error: one path skips constructor:


class Foo2
{
   this(bool b)
   {
     if(b)
       val=14;
     else
       this(); //<< crucial line
   }

   this()
   {
     val=7;
   }

protected:
   int val;
}


Why is the constructor in Foo1 acceptable, while the one in Foo2 is not?
I believe this is a bug.
Actually, it is designed to work that way. The semantic phase does a rather primitive data flow analysis to determine that if another constructor is called on one path through the constructor, it must be called on all paths through.
So how can I circumvent this? In my real world example I don't want to call the default constructor because that would cause a lot of unnecessary stuff to happen (like allocating memory that is thrown away right afterwards). Do I have to write a empty bogus constructor overload with an invented list of parameters that I can call from the first code path? That would be SUCH a hack... This is one of the things you always wanted to prevent in D. I know this code is right and I just want the compiler to shut up :(. And it is also very similar to requiring returns in all code paths. Why do you allow missing returns, but you don't allow missing constructor calls? At least in the return case it is easy to "make the compiler shut up". In the constructor case I don't even know how, except for that ugly invented empty constructor hack. Hauke
Jan 10 2004
parent reply "Walter" <walter digitalmars.com> writes:
"Hauke Duden" <H.NS.Duden gmx.net> wrote in message
news:btota8$1ijf$1 digitaldaemon.com...
 So how can I circumvent this? In my real world example I don't want to
 call the default constructor because that would cause a lot of
 unnecessary stuff to happen (like allocating memory that is thrown away
 right afterwards).

 Do I have to write a empty bogus constructor overload with an invented
 list of parameters that I can call from the first code path? That would
 be SUCH a hack...

 This is one of the things you always wanted to prevent in D. I know this
 code is right and I just want the compiler to shut up :(.

 And it is also very similar to requiring returns in all code paths. Why
 do you allow missing returns, but you don't allow missing constructor
 calls? At least in the return case it is easy to "make the compiler shut
 up". In the constructor case I don't even know how, except for that ugly
 invented empty constructor hack.
It's an interesting tradeoff, adding in the dummy constructor in one case, and leaving in a potential large source of inadvertent bugs. I think the thing to do is wait and see how things evolve a bit.
Jan 17 2004
parent reply Hauke Duden <H.NS.Duden gmx.net> writes:
Walter wrote:
 "Hauke Duden" <H.NS.Duden gmx.net> wrote in message
 news:btota8$1ijf$1 digitaldaemon.com...
 
So how can I circumvent this? In my real world example I don't want to
call the default constructor because that would cause a lot of
unnecessary stuff to happen (like allocating memory that is thrown away
right afterwards).

Do I have to write a empty bogus constructor overload with an invented
list of parameters that I can call from the first code path? That would
be SUCH a hack...

This is one of the things you always wanted to prevent in D. I know this
code is right and I just want the compiler to shut up :(.

And it is also very similar to requiring returns in all code paths. Why
do you allow missing returns, but you don't allow missing constructor
calls? At least in the return case it is easy to "make the compiler shut
up". In the constructor case I don't even know how, except for that ugly
invented empty constructor hack.
It's an interesting tradeoff, adding in the dummy constructor in one case, and leaving in a potential large source of inadvertent bugs. I think the thing to do is wait and see how things evolve a bit.
I hereby make a motion to introduce the keyword "shaddap", that makes the compiler stop complaining about these kinds of warnings-turned-errors ;). Hauke
Jan 18 2004
parent Vathix <vathix dprogramming.com> writes:
Hauke Duden wrote:
 
 I hereby make a motion to introduce the keyword "shaddap", that makes 
 the compiler stop complaining about these kinds of 
 warnings-turned-errors ;).
 
 Hauke
There's a switch for this, that big button on your computer case :>
Jan 18 2004
prev sibling parent reply Andy Friesen <andy ikagames.com> writes:
Hauke Duden wrote:
 This works:
 
 [...]

 Why is the constructor in Foo1 acceptable, while the one in Foo2 is not? 
 I believe this is a bug.
 
 Hauke
Foo2 shouldn't have to (shouldn't be *able* to!) rely on the internal representation of Foo1. What you're doing is very dangerous from a design or maintenance perspective. I'm almost ready to say that it should be an error if each of Foo2's constructors do not call exactly one Foo1 constructor. What you should do is something more like: class Foo1 { // uber-paranoid. Use the accessor even internally. this(int v) { val = v; } this() { this(0); } int val() { return _val; } void val(int v) { _val = v; } private: // not protected int _val; } class Foo2 { this(bool b) { if (b) super(); else super(17); } } Of course, this is all effectively religious dogma, but I'd say it's a very good thing if Foo2 is completely incapable of breaking because of changes to Foo1's implementation. -- andy
Jan 17 2004
parent Hauke Duden <H.NS.Duden gmx.net> writes:
Andy Friesen wrote:
 Hauke Duden wrote:
 
 This works:

 [...]

 Why is the constructor in Foo1 acceptable, while the one in Foo2 is 
 not? I believe this is a bug.

 Hauke
Foo2 shouldn't have to (shouldn't be *able* to!) rely on the internal representation of Foo1. What you're doing is very dangerous from a design or maintenance perspective.
While this may be true in many cases, it is not in this particular case. The base class actually does not have a constructor, because it is a completely abstract class. It doesn't even have any member variables, it is only there to provide default implementations for some interface functions. This kind of implementation helper for an interface is often a very big help. Besides: the problem was not that I called a base class constructor - I called another constructor of the same class in one code branch and didn't in another. Hauke
Jan 18 2004