1

In this question C# constructor execution order, the main answer mentioned that

Note that in Java, the base class is initialized before variable initializers are run. If you ever port any code, this is an important difference to know about

I want to know that are there real examples that you can't simply port between C# constructor and Java constructor because of this issue?

If so, are these examples only deliberately designed anti-patterns or do they exist in real projects like some open source projects?

Update: Can we make a list of patterns that can't be ported simply, e.g. prove that if there are no such patterns in the code, the constructor can be mapped simply with tools.

My try (with help from @John): according to a comment of that answer, the code bellow can't be ported simply, but it is deliberately designed:

C#:

class foo
{
    public foo()
    {
        if (this is bar)
        {
            (this as bar).test();
        }
    }
}

class bar : foo
{
    string str="str" ;
    public bar()
    {

    }

    public void test()
    {
        string s=str.Substring(1);
    }
}

Java:

static public class foo
{
    public foo()
    {
        if (this instanceof bar)
        {
            ((bar)this).test();
        }
    }
}

static public class bar extends foo
{
    String str="str" ;
    public bar()
    {

    }

    public void test()
    {
        String s=str.substring(1);
    }
}
jw_
  • 1,663
  • 18
  • 32
  • I made a [Java version](https://pastebin.com/e8rt3GEv) if you want to add it to your question. But yes, I observed the same behaviour - `str` was null. – ProgrammingLlama Sep 03 '19 at 02:39

1 Answers1

2

On the answer you've linked to, Jon Skeet provides a link to "a page with more details", in which he uses this example:

public class MyBaseClass
{
    public MyBaseClass ()
    {
        Console.WriteLine (this.ToString());
    }
}

public class MyDerivedClass : MyBaseClass
{
    string name="hello";
    
    public MyDerivedClass() : base()
    {
        Console.WriteLine (this.ToString());
    }

    public override string ToString()
    {
        return name;
    }
}

When a new instance of MyDerivedClass is created in C#, the output is:

hello
hello

The first line is hello because the instance variable initializer for the name variable has run directly before the base class constructor. The equivalent code in Java syntax would output:

null
hello 

I wouldn't consider this example to be particularly contrived: it's not unthinkable that someone would call a virtual method (like ToString()) in a base class, nor that a virtual method would try to use a member variable. In fact, it wouldn't be very far-fetched to assume that this is something Jon might have run into personally, considering he has authored libraries and their ports in both languages.

But, as he mentions:

This is a really bad idea - wherever possible, only call non-virtual methods from constructors, and if you absolutely must call a virtual method, document very carefully that it is called from the constructor, so that people wishing to override it are aware that their object may not be in a consistent state when it is called (as their own constructor won't have run yet).

So anti-pattern: yes. Deliberately designed? Perhaps not.

Community
  • 1
  • 1
StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315