Call to another constructor must be the first statement in constructor block

I believe you should be doing it this way:

public class MyClass
{
    final String someProperty;
    public MyClass()
    {
        /* some default logic */
    }
    public MyClass(String someProperty)
    {
        this();
        this.someProperty = someProperty;
    }
}

Call the constructor for the object and set the property on the object separately.

The reason you can't chain a constructor call with another method is that the constructor call doesn't have a return type.

If you had a different instance method on the object that returned this, you would be able to chain those two method calls together.

public class MyClass
{
    String someProperty;
    public MyClass returnThis(){
        return this;
    }
    public MyClass(String someProperty)
    {
        returnThis().someProperty = someProperty;
    }
}

this() behaves differently than new MyClass() because the new operator returns the reference to the object created. When doing constructor chaining with this(), it just runs the other constructor subroutine, and doesn't return a reference to the object being constructed. You can't do this().someProperty just like you can't chain methods that return void: new list<String>().add('s').add('t');


I think this speaks somewhat to Apex inheriting so much from Java.

Try the same thing with a Java compiler:

public class HelloDog
{
  public static void main(String[] args)
  {
    Dog myDog = new Dog();
    System.out.print(myDog);
  }
}

class Dog{
    protected String name;

    public Dog(){
        this("Fido").name="Arf"; 
        //this.name="Arf";
        System.out.println("Inside no argument constructor of Dog class");
    }

    public Dog(String name){
        this.name = name;
        System.out.println("One arg constructor of Dog class");
    }
}

Gives the following compiler errors:

/HelloDog.java:15: error: call to this must be first statement in constructor

this("Fido").name="Arf";
. ^

/HelloDog.java:15: error: void cannot be dereferenced
this("Fido").name="Arf";
. ^

As Martin answered, the chained constructor returns void rather than the instance, so you can't chain anything to it.

Calling the constructor and constructor chaining are two different things with very similar syntax.

Personally I think the C# syntax makes constructor chaining clearer. Rather than being a special case of this that appears at the start of the constructor it has it's own explicit syntax:

class Dog {
    protected String name;

    public Dog() : this("Fido")
    {
    }

    public Dog(String name){
        this.name = name;
    }
}

If you tried to do a public Dog() : this("Fido").name="arf" { in C# the compiler will look at you funny and ask where the missing { is. The constructor chaining here isn't a statement that can end in a semicolon. It's telling the compiler to chain the constructors together.


Summary: Your initial assumption was (kind of) wrong. Which led to some interesting findings. Read on.

Consider the following code:

class DoNothing { Integer value; }
Integer getInt() {
    return 5 / 0;
}
Object o;
((DoNothing)o).value = getInt();

We have a pending NullPointerException and a pending MathException. Which one happens first? In actuality, the MathException happens first. More specifically, your assumption about the order of operations was incorrect.

Let's get to a basic example of where that could lead to a surprise:

class A() {
  String value;
  A() {
    this('Hello').value = value + value;
  }
  A(String v) {
    value = v;
  }
}

What should value be? "HelloHello"? Nope, it would be "nullnull" (assuming this code were allowed to compile). That's because the right-hand was evaluated first, cached, then the left-side was evaluated, and then the concatenation/assignment operator was applied using the null value. We were depending on value being evaluated later, but it was not.

(Edit: I noticed that += actually does work correctly. Adding demos.)

Here's an example of the caching effect in play:

public class exampleValueSet {
    public String value;
    public exampleValueSet setValue(String v) {
        value = v;
        return this;
    }
}
exampleValueSet v = new exampleValueSet();
v.setValue('world').value = v.value + v.value;
system.debug(v.value);

While using += results in the intended result:

public class exampleValueSet {
    public String value;
    public exampleValueSet setValue(String v) {
        value = v;
        return this;
    }
}
exampleValueSet v = new exampleValueSet();
v.setValue('world').value += v.value;
system.debug(v.value);

Note that the Order of Operations manual specifically says that the assignment operators evaluate last. This can cause the timing for when a value is evaluated to change. For example += v.value + v.value yields a different result than += v.value. Unless you're 100% certain of how side effects will occur, it's best to avoid trying to introduce them to your code. It gets pretty complicated quickly.

Worse, if they allowed code like this, and later decided to change the order of operations, then code that depended on the current order might break. To avoid any ambiguity, they just blocked it altogether.

It's a very powerful block, too. It supersedes all other errors I tested it against:

Unary increment/decrement can only be applied to numeric expressions

this(5)++;

Arithmetic expressions must use numeric arguments

this() / 5;

Comparison arguments must be compatible types

this() == 5;

Expression cannot be a statement

this() == this;

Object has no superclass for super invocation

super() == this;

All of those errors, in any other context, are replaced by the same Call to another constructor must be the first statement in constructor block error when applied to this() or super(). It even beats out super()'s "no superclass" error; this error is literally thrown even before types are checked or anything else.


Also, interestingly, they've specifically blocked using parameters that lead to instance methods or variables. So, you can't do this either:

public class A {
  public Integer b;
  public A() {
    this(b=5);
  }
  public A(Integer v) {
    b = v * 2;
  }
}

Which would normally be valid code if called on a normal method (5 would be assigned to b, and then 5 would be multiplied by 2, leaving b as 10).

In that case, we get a different error:

cannot reference instance variables or instance methods inside a constructor invocation

Unless, of course, you cause the "Call to another constructor..." error, as before.