4

I am currently porting the class NumberRange from Java to C#.

I am writing this constructor and I wonder whether I can call a constructor in itself. Something like this:

public NumberRange(Double num1, Double num2)
{
    if (num1 <= num2)
    {
        Min = num1;
        Max = num2;
    }
    else
    {
        NumberRange(num2, num1);
        // Min = num2;
        // Max = num1;
    }
}

.NETFiddle

This is not a big deal, but I am curious. I think it is to prevent messing with constructor by creating a Stack Overflow during a class creation.

So, why can't I call a constructor in itself?

Edit:

I remind that my question was about the "why" and not the "how". If you ask yourself how I implemented this, just read my code here.

  • I think this is only a C# and not a .NET restriction, AFAIR Spec# allows (base) constructor calls in the middle of a constructor. – CodesInChaos Sep 11 '15 at 10:04
  • 1
    I think the reason C# forbids this is to make reasoning about the constructor easier. For example these restrictions guarantee that the base class constructor runs exactly once and that it runs before the (user written code of the) derived class constructor runs. – CodesInChaos Sep 11 '15 at 10:06
  • 2
    As this is a simple example the more reliable solution might not be obvious. If you have a case where the order of the arguments is not obvious to the caller, but it is convenient for the object to be created with the arguments in the right order, then why not move the responsibility for ordering the arguments to a factory method. That would then return an object created correctly. Consider a case of a pentagon, where you would like the corners supplied to be in clockwise order to make it easier to draw later, but the user can enter the points in counter clockwise order (or any order). – Bent Sep 11 '15 at 10:48
  • Calling constructor asside, be careful about the piece of code you wrote. Even if you manage to call a constructor within a constructor, your current version will lead to a never-ending loop and will terminate your application. – Andy Sep 11 '15 at 13:02
  • @DavidPacker I dont saw the never-ending loop problem? I think my statement will handle it. – aloisdg says Reinstate Monica Sep 11 '15 at 13:20
1

The issue seems to be not the recursion, but with invoking the constructor at all. See below:

class NumberRange
{
    public double Min { get; set; }
    public double Max { get; set; }

    public NumberRange(double num1, double num2)
    {
        if (num1 <= num2)
        {
            Min = num1;
            Max = num2;
        }
        else
            NumberRange(num2, num1); // illegal!!
    }

    public void AFunction()
    {
        NumberRange(1, 2); // also illegal!!
        this.NumberRange(1, 2); // 'this' keyword doesn't help
    }
}

And:

new NumberRange(1, 2).NumberRange(2, 1); // can't invoke the constructor on an object either

Obviously in your case the recursion was completely unnecessary, but if you have code which must be "recursable" - or just available outside of the context of instantiating a class - that code must be in a non-constructor function.

See this answer for why it is OK to call methods from constructors in C#. (In short, C# handles virtual method calls in ctors as one might hope.)

  • I finish to do this, calling a private method. I will accept this because it the nearest answer to the why I got. – aloisdg says Reinstate Monica Jul 6 '16 at 20:58
6

You can call a constructor from a constructor but you need a different syntax and to call a different constructor. I intentionally changed the signature for the private constructor to differentiate the two. It isn't good in this example since they should logically have the same signature

public NumberRange(Double num1, Double num2) 
    : this(Math.Min(num1, num2), Math.Max(num1, num2), true) { }
private NumberRange(Double num1, Double num2, bool differentSignature){         
    Min = num1; 
    Max = num2;
}
  • 1
    This is clever. – aloisdg says Reinstate Monica Sep 11 '15 at 13:13
  • 9
    @Sign I know you wrote this example as an illustration for how you could call a different constructor based on the code in the question. But I'm shuddering as something beyond horrible has just walked across my grave. Kids, grown-ups do not do this in your code, whether at home or not. – Bent Sep 11 '15 at 13:24
  • 1
    Firstly, this is horrible! :-) Secondly, the question was "why can't I call a constructor in itself?" and you haven't answered that. Still, pretty creative thinking - but you thought too hard about if you can, and forgot to consider whether you should, and now you're going to hell. ;-) – Grimm The Opiner Sep 14 '15 at 15:49
-1

You could technically use Label and goto statements to essentially run the recursion with out worrying about stackOverflow

class NumberRange {
    public double Min { get; set; }
    public double Max { get; set; }

    public NumberRange(double num1, double num2) {
        DOTHIS:
        if (num1 <= num2) {
            Min = num1;
            Max = num2;
        } else {
            double num = num1;
            num1 = num2;
            num2 = num;
            goto DOTHIS;
        }
    }
}

Then Executing the following at the Console does this:

NumberRange nr = new NumberRange(10, 5);
nr.Min

RETURNS 5

nr.Max

RETURNS 10

This won't at all answer why, but I figured that it would be helpful to see another version of HOW

class NumberRange {
    private double _Min { get; set; }
    private double _Max { get; set; }
    private bool swap { get; set; }
    public double Min {
        get {
            if (!swap) { return _Min; } else { return _Max; }
        }
        set {
            _Min = value;
            if (value <= _Max) { swap = false; } else { swap = true; }
        }
    }
    public double Max {
        get {
            if (swap) { return _Min; } else { return _Max; }
        }
        set {
            _Max = value;
            if (value > _Min) { swap = false; } else { swap = true; }
        }
    }

    public NumberRange(double num1, double num2) {
        Min = num1;
        Max = num2;
    }
}

Then Executing the following at the Console does this:

NumberRange myNumRange_1 = new NumberRange(5, 10);
Console.WriteLine(myNumRange_1.Min + "");

RETURNS: 5

myNumRange_1.Min = 15;
Console.WriteLine(myNumRange_1.Min + "");

RETURNS: 10

  • I hope you realize that I'm using this answer to challenge the answer provided. Technically, you are not allowed to flat out call the constructor again recursively (but WHY not?), You can recursively implement this if you are careful (just as you have to be careful not to enter into endless loops, and stackOverflow errors in general, etc...). All this to say, that on a technicality, you can't do this in the assumed way that recursion "should be expected" to happen, but you CAN essentially use recursion. So my answer to your WHY is WHY NOT. – Rick Riggs Aug 23 '18 at 17:21
  • I would like to know why someone thought this wasn't helpful to the context of this question (I'm not offended by any means, but I really want to know). The question is specifically about why recursion isn't possible inside of the constructor, when calling itself. I'm showing that this very intent is very possible with recursion. The only real difference is, I'm adding nothing new to the stack (awesome), but I'm still having it call reference to itself upon the stated conditions (And gave more than one proven example - One with recursion, one without based on getter and setter logic). – Rick Riggs Aug 23 '18 at 21:20
  • This is a very bad engineer approach, I discourage the usage, but I like the challenge, in fact you have provided a correct and working sample. – Stefano Balzarotti Nov 7 '18 at 11:29
  • @StefanoBalzarotti Why would you consider this a bad approach? Is this just gut feel, or is there solid engineering principles that I am not considering (oblivious to) in the context of my answer? – Rick Riggs Nov 12 '18 at 21:26
-4

You cant call a constructor within itself same as you cant call struct in its own struct, because when you call a constructor space and value get assigned to the object. When constructor is called within the constructor it keeps on looping that's why they prohibited such a thing. Even though it seems easy and possible its not the case for all the time.

  • 1
    Any outside source? – aloisdg says Reinstate Monica Sep 11 '15 at 13:29
  • If the constructor has a parameter it can also create an end-condition, closing the recursion. Just like any other recursive function out there. – Abel Oct 27 '17 at 9:18
-5

EDIT2: It's seems like it's not possible and I was mistaken. Probably confused two things I did in the past. I apologise.

You can call a constructor in itself, but you call it by writing

new ClassName(arg1, arg2);

like in writing

public Constructor(int a1, int a2)
{
    if(a1<a2) return new Class(a2, a1);
}

EDIT: Sorry I was wrong about the this();

  • I dont think it is possible in my case. You are talking about this, arent you? – aloisdg says Reinstate Monica Sep 11 '15 at 9:53
  • I edited it, now it should be correct, sorry. – hstde Sep 11 '15 at 10:07
  • 2
    You cant return from a constructor since return type is void. – Esben Skov Pedersen Sep 11 '15 at 10:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.