[PYTHON] The story that inheritance behavior is quite different in each language

Introduction

This article is a compilation of the results of my research into what values are actually output by writing class inheritance in different languages in a similar way. Sometimes I worked hard from Hello World, thinking that there was such a grammar even in a known language.

Who would benefit from it being difficult to put together? However, I will leave it for those who are interested in the same thing. No, there may be new discoveries, so please read it for the time being. It may have been a surprisingly interesting result.

Language examined

--Static typing

--Dynamic typing

--Optional static typing

Code used in the survey

A child class inherits a parent class. Its parent and child classes have instance variables with the same name. (Not a class variable) The parent class has a method that you can use to output instance variables to the console.

At run time, the child class instance calls the inherited parent method. Now, the story is ** Which instance variable, parent or child, will be output ** …….

If you write it in JS (ES6 or later) code that many people can probably read, it is such a code.

class SuperClass {
  constructor() {
    //* In JS, instance variables are defined at runtime, so write them in the constructor.
    this.instanceVariable = "SuperClass" //Different values with the same name
  }

  superClassMethod() {
    console.log(this.instanceVariable)
  }
}

class SubClass extends SuperClass {
  constructor() {
    super()
    this.instanceVariable = "SubClass" //Different values with the same name
  }
}

const sub = new SubClass() //Intensify child class
sub.superClassMethod() //Call the inherited parent class method

Imagine what values are output in the language you normally use. It's an occasional writing style (good or bad), so you may know what you're good at. But if you know how it works in other languages, it may be useful someday when you enter another company or a different project, or when you are interested in getting started in another language.

This time, I'm looking at not only instance variables but also what happens when you do return" SuperClass " with a method (a method of an instance that is not a class method). In this case, the parent class and the child class have a method with the same name, and the method of the parent class calls it ....

You can find out what kind of code you wrote and looked up.

View code (hoge language)
class Hoge {}

Since the detailed folding element is placed like this, you can read the code inside by clicking it to open it. It's a pretty WET code that uses copy and paste in principle to make it easier to see what you're doing, but don't throw the chords as it's intentional.

This time's point

As you know, different programming languages have different grammars and different evaluation methods. I think the points that will change the results this time are as follows.

--Does the access modifier exist? Also, what kind of things are there --Can instance variables with the same name be defined in the parent class and child class in the first place? --Are there instance variable overrides and method overrides? ――How each language handles inheritance itself

Result announcement

Java

Java, the champion of enterprise systems. Java has access modifiers such as private and protected. private can only be seen from the current class. protected can be accessed by the current class and its child classes.

There are no instance variable overrides in Java. So let's see what happens when we override it with a method.

conditions result
Instance variable is private "SuperClass"
Instance variables are protected "SuperClass"
Private methods instead of instance variables "SuperClass"
Protected method (override) instead of instance variable "SubClass"

Overrides literally "override".

This time it didn't matter, but Java can access the instance variables of the parent class with methods on the child class side like super.instanceVariable. It's a trick that you can do because you don't override it.

View code (Java)
public class JavaSample {
    public static void main(String[] args) {
        System.out.println("---- SubClass ----");
        SubClass sub = new SubClass();
        sub.superClassMethod();

        System.out.println("---- SubClassProtected ----");
        SubClassProtected subp = new SubClassProtected();
        subp.superClassMethod();

        System.out.println("---- SubClassGetter ----");
        SubClassGetter subg = new SubClassGetter();
        subg.superClassMethod();

        System.out.println("---- SubClassGetterProtected ----");
        SubClassGetterProtected subgp = new SubClassGetterProtected();
        subgp.superClassMethod();
    }
}

class SuperClass {
    //Private instance variables cannot be referenced by subclasses
    private String instanceVariable = "SuperClass";

    public void superClassMethod() {
        System.out.println(instanceVariable);
    }
}

class SubClass extends SuperClass {
    private String instanceVariable = "SubClass";
}

// -------------------------------------------

class SuperClassProtected {
    protected String instanceVariable = "SuperClass";

    public void superClassMethod() {
        System.out.println(instanceVariable);
    }
}

class SubClassProtected extends SuperClassProtected {
    protected String instanceVariable = "SubClass";

    // public void subClassMethod() {
        // System.out.println(instanceVariable);If you write
        // System.out.println(this.instanceVariable);Same as."SubClass"coming out.
        //With super,"SuperClass"Can also be displayed
        // System.out.println(super.instanceVariable);
    // }
}

// -------------------------------------------

class SuperClassGetter {
    private String instanceVariable() {
        return "SuperClass";
    }

    public void superClassMethod() {
        System.out.println(instanceVariable());
    }
}

class SubClassGetter extends SuperClassGetter {
    private String instanceVariable() {
        return "SubClass";
    }
}

// -------------------------------------------

class SuperClassGetterProtected {
    protected String instanceVariable() {
        return "SuperClass";
    }

    public void superClassMethod() {
        System.out.println(instanceVariable());
    }
}

class SubClassGetterProtected extends SuperClassGetterProtected {
    protected String instanceVariable() {
        return "SubClass";
    }
}

C#

After Java, after all C #. It has a grammar that is quite similar to Java for historical reasons. The result is also similar to Java and C ++ described below, but there are some that Java does not have. By the way, C # has properties, so I wrote them as properties instead of methods.

There are virtual and ʻoverridein C #.virtual is a qualifier that tells you that this method can be overridden, and ʻoverride is a qualifier that tells you that the method is overriding here.

That's fine, but C # also has a weird qualifier called new. This new is different from the new of new Human () at the time of instantiation. By adding new instead of override, the method of the parent class can be evaluated in the context of the parent class even if it is called from the child class. The reason is that we are not overriding the methods of the parent class, we are just hiding them. It's complicated.

conditions result
Instance variable is private "SuperClass"
Instance variables are protected "SuperClass"
Property is private "SuperClass"
Property protected(override) "SubClass"
Property protected(new) "SuperClass"
View code (C #)
using System;

public class CSharpSample
{
    public static void Main(string[] args)
    {
        Console.WriteLine("---- SubClass ----");
        var sub = new SubClass();
        sub.SuperClassMethod();

        Console.WriteLine("---- SubClassProtected ----");
        var subp = new SubClassProtected();
        subp.SuperClassMethod();

        Console.WriteLine("---- SubClassGetter ----");
        var subg = new SubClassGetter();
        subg.SuperClassMethod();

        Console.WriteLine("---- SubClassGetterProtectedOverride ----");
        var subgpo = new SubClassGetterProtectedOverride();
        subgpo.SuperClassMethod();

        Console.WriteLine("---- SubClassGetterProtectedNew ----");
        var subgpn = new SubClassGetterProtectedNew();
        subgpn.SuperClassMethod();
    }
}

class SuperClass
{
    private string instanceVariable = "SuperClass";

    public void SuperClassMethod()
    {
        Console.WriteLine(instanceVariable);
    }
}

class SubClass : SuperClass
{
    // warning CS0414: The field 'SubClass.instanceVariable' is assigned but its value is never used
    private string instanceVariable = "SubClass";
}

// ----------------------------

class SuperClassProtected
{
    protected string instanceVariable = "SuperClass";

    public void SuperClassMethod()
    {
        Console.WriteLine(instanceVariable);
    }
}

class SubClassProtected : SuperClassProtected
{
    //new is not an override, it explicitly states that it hides the instance variable of the inheritance source
    new protected string instanceVariable = "SubClass";
}

// ----------------------------

class SuperClassGetter
{
    private string instanceVariable
    { 
        get { 
            return "SuperClass";
        }
    }

    public void SuperClassMethod()
    {
        Console.WriteLine(instanceVariable);
    }
}

class SubClassGetter : SuperClassGetter
{
    private string instanceVariable {
        get {
            return "SubClass";
        }
    }
}

// ----------------------------

class SuperClassGetterProtected
{
    protected virtual string instanceVariable
    { 
        get { 
            return "SuperClass";
        }
    }

    public void SuperClassMethod()
    {
        Console.WriteLine(instanceVariable);
    }
}

class SubClassGetterProtectedOverride : SuperClassGetterProtected
{
    protected override string instanceVariable {
        get {
            return "SubClass";
        }
    }
}

class SubClassGetterProtectedNew : SuperClassGetterProtected
{
    protected new string instanceVariable {
        get {
            return "SubClass";
        }
    }
}

C++

It seems that C ++ is often used in embedded sites, but I don't know anything. C ++ Nanimowa Karanai …….

Along with Java, it is the original language of C #, so its behavior is very similar to C #. If you use a method instead of an instance variable and do not override it, it behaves the same as new in C #.

conditions result
Instance variable is private "SuperClass"
Instance variables are protected "SuperClass"
Private methods instead of instance variables "SuperClass"
Protected method (override) instead of instance variable "SubClass"
Protected method instead of instance variable (do not override) "SuperClass"
View code (C ++)
#include <iostream>

class SuperClass {
//Private by default (inaccessible from outside the class)
    std::string instanceVariable = "SuperClass";
public:
    void superClassMethod() {
        std::cout << instanceVariable << std::endl;
    }
};

class SubClass : public SuperClass {
    std::string instanceVariable = "SubClass";
};

// -------------------------------

class SuperClassProtected {
protected:
    std::string instanceVariable = "SuperClass";
public:
    void superClassMethod() {
        std::cout << instanceVariable << std::endl;
    }
};

class SubClassProtected : public SuperClassProtected {
protected:
    std::string instanceVariable = "SubClass";
};

// -------------------------------

class SuperClassGetter {
    std::string instanceVariable() {
        return "SuperClass";
    }
public:
    void superClassMethod() {
        std::cout << instanceVariable() << std::endl;
    }
};

class SubClassGetter : public SuperClassGetter {
    std::string instanceVariable() {
        return "SubClass";
    }
};

// -------------------------------

class SuperClassProtectedGetter {
protected:
    std::string instanceVariable() {
        return "SuperClass";
    }
public:
    void superClassMethod() {
        std::cout << instanceVariable() << std::endl;
    }
};

class SubClassProtectedGetter : public SuperClassProtectedGetter {
protected:
    std::string instanceVariable() {
        return "SubClass";
    }
};

// -------------------------------

class SuperClassProtectedGetterOverride {
protected:
    virtual std::string instanceVariable() {
        return "SuperClass";
    }
public:
    void superClassMethod() {
        std::cout << instanceVariable() << std::endl;
    }
};

class SubClassProtectedGetterOverride : public SuperClassProtectedGetterOverride {
protected:
    std::string instanceVariable() override {
        return "SubClass";
    }
};

int main()
{
    std::cout << "---- SubClass ----" << std::endl;
    SubClass sub;
    sub.superClassMethod();

    std::cout << "---- SubClassProtected ----" << std::endl;
    SubClassProtected subp;
    subp.superClassMethod();

    std::cout << "---- SubClassGetter ----" << std::endl;
    SubClassGetter subg;
    subg.superClassMethod();

    std::cout << "---- SubClassProtectedGetter ----" << std::endl;
    SubClassProtectedGetter subpg;
    subpg.superClassMethod();

    std::cout << "---- SubClassProtectedGetterOverride ----" << std::endl;
    SubClassProtectedGetterOverride subpgo;
    subpgo.superClassMethod();

    return 0;
}

Scala

AltJava that incorporates a functional style. The big difference from Java and C # is that you can ** override instance variables **. New features are here!

conditions result
Instance variable is private "SuperClass"
Instance variable protected (override) "SubClass"
View code (Scala)
object ScalaSample {
    def main(args: Array[String]): Unit = {
        println("---- SubClass ----")
        val sub = new SubClass
        sub.superClassMethod()
    
        println("---- SubClassProtected ----")
        val subp = new SubClassProtected
        subp.superClassMethod()
    }
}

class SuperClass {
    private val instanceVariable = "SuperClass";

    def superClassMethod(): Unit = {
        println(instanceVariable);
    }
}

class SubClass extends SuperClass {
    private val instanceVariable = "SubClass";
}

// ----------------------------

class SuperClassProtected {
    protected val instanceVariable = "SuperClass";

    def superClassMethod(): Unit = {
        println(instanceVariable);
    }
}

class SubClassProtected extends SuperClassProtected {
    override protected val instanceVariable = "SubClass";
}

Kotlin

Alt Java was heavily influenced by Scala. It is often used in the development of Android applications. Same as Scala, except that you must add open to the instance variable you plan to override. So ʻopen is like virtual` in C ++ or C #.

conditions result
Instance variable is private "SuperClass"
Instance variable protected (override) "SubClass"
View code (Kotlin)
fun main(args: Array<String>) {
    println("---- SubClass ----");
    val sub = SubClass();
    sub.superClassMethod();

    println("---- SubClassOverride ----");
    val subo = SubClassOverride();
    subo.superClassMethod();
}

open class SuperClass {
    private val instanceVariable = "SuperClass";

    fun superClassMethod() {
        println(instanceVariable);
    }
}

class SubClass : SuperClass() {
    private val instanceVariable = "SubClass";
}

// -----------------------------------

open class SuperClassOverride {
    open val instanceVariable = "SuperClass";

    fun superClassMethod() {
        println(instanceVariable);
    }
}

class SubClassOverride : SuperClassOverride() {
    override val instanceVariable = "SubClass";
}

Swift

Android is not the only app. I don't want you to forget iOS. It seems that the behavior of Swift's private changes depending on the version, but this time I verified it with Swift 5, so like Java, it is valid only in the class and is not inherited.

Swift's let is a variable declaration that prohibits reassignment. In JS, it is const. And Swift's var is a normal variable declaration that can be reassigned. It is let in JS. It's complicated.

In Swift, you can't define an instance variable (called a property in Swift) that is the same as the inheritance source. You can override it by using Computed Property (like a property in C #) instead.

Without an access modifier like private, the scope is ʻinternal. ʻInternal is like public in Java (miscellaneous).

conditions result
Instance variable is private "SuperClass"
Instance variable is internal Undefinable
Computed Property is private "SuperClass"
Computed Property is internal(override) "SubClass"
View code (Swift)
class SuperClass {
  private let instanceVariable = "SuperClass";

  func SuperClassMethod() {
    print(instanceVariable);
  }
}

class SubClass: SuperClass {
  private let instanceVariable = "SubClass";
}

// --------------------------------

class SuperClassInternal {
  let instanceVariable = "Error";

  func SuperClassMethod() {
    print(instanceVariable);
  }
}

class SubClassInternal: SuperClassInternal {
  // error: cannot override with a stored property 'instanceVariable'
  // let instanceVariable = "SubClass";
}

// --------------------------------

//Make it a Computed Property and grow a getter. In this case, it is treated as a function, so you can override it.
class SuperClassGetter {
  //If it is let, error: 'let' declarations cannot be computed properties
  private var instanceVariable: String { get { return "SuperClass" } }

  func SuperClassMethod() {
    print(instanceVariable);
  }
}

class SubClassGetter: SuperClassGetter {
  private var instanceVariable: String { get { return "SubClass" } };
}

// --------------------------------

//Make it a Computed Property and grow a getter. In this case, it is treated as a function, so you can override it.
class SuperClassInternalGetter {
  //If it is let, error: 'let' declarations cannot be computed properties
  var instanceVariable: String { get { return "SuperClass" } }

  func SuperClassMethod() {
    print(instanceVariable);
  }
}

class SubClassInternalGetter: SuperClassInternalGetter {
  override var instanceVariable: String { get { return "SubClass" } };
}

print("---- SubClass ----");
let sub = SubClass();
sub.SuperClassMethod();

print("---- SubClassInternal ----");
let subi = SubClassInternal();
subi.SuperClassMethod();

print("---- SubClassGetter ----");
let subg = SubClassGetter();
subg.SuperClassMethod();

print("---- SubClassInternalGetter ----");
let subig = SubClassInternalGetter();
subig.SuperClassMethod();

Python

From here on, a dynamically typed language! Python has made its popularity solid, such as continuing to take first place in Qiita's tag posting ranking.

The characteristic of Python class is that the instance itself comes to the first argument of the method, so when declaring it, write self as the first argument. It doesn't have to be self, but everyone writes self.

After that, like a dynamically typed language, instance variables are dynamically created, so define the instance variables in the constructor instead of directly under the class declaration. This is the same for Ruby and JavaScript.

Python has no member access restrictions. There is no qualifier private. It is a culture that puts ** 1 ** underscore at the beginning of the function name to indicate that you do not want to access it.

But in Python, there is a feature in case there is a name conflict with a child class. Adding ** 2 ** underscores changes the internal member name (name mangling), making it easy to make the original variable name inaccessible. This feature allows you to evaluate the result at run time in the context of the original parent class, even if the child class has members with the same name. pep8-ja --naming convention --method name and instance variable Let's see the result.

conditions result
Instance variables "SubClass"
Method instead of instance variable "SubClass"
Instance variable (with 2 Ansco) "SuperClass"
Method instead of instance variable (with 2 Ansco) "SuperClass"
View code (Python)
class SuperClass:
  def __init__(self):
    self.instance_variable = "SuperClass"

  def super_class_method(self):
    print(self.instance_variable)

class SubClass(SuperClass):
  def __init__(self):
    super().__init__()
    self.instance_variable = "SubClass"

# ------------------------------

class SuperClassNameMangling:
  def __init__(self):
    self.__instance_variable = "SuperClass"

  def super_class_method(self):
    print(self.__instance_variable)

class SubClassNameMangling(SuperClassNameMangling):
  def __init__(self):
    super().__init__()
    self.__instance_variable = "SubClass"

# ------------------------------

class SuperClassGetter:
  def instance_variable(self):
    return "SuperClass"

  def super_class_method(self):
    print(self.instance_variable())

class SubClassGetter(SuperClassGetter):
  def instance_variable(self):
    return "SubClass"

# ------------------------------

class SuperClassNameManglingGetter:
  def __instance_variable(self):
    return "SuperClass"

  def super_class_method(self):
    print(self.__instance_variable())

class SubClassNameManglingGetter(SuperClassNameManglingGetter):
  def __instance_variable(self):
    return "SubClass"

print('---- SubClass ----')
sub = SubClass()
sub.super_class_method()

print('---- SubClassNameMangling ----')
subp = SubClassNameMangling()
subp.super_class_method()

print('---- SubClassGetter ----')
subg = SubClassGetter()
subg.super_class_method()

print('---- SubClassNameManglingGetter ----')
subpg = SubClassNameManglingGetter()
subpg.super_class_method()

Ruby

"What about an object-oriented dynamically typed language?" Many programmers who took the associative quiz think of this language first.

Ruby has a private that can be used for methods, but it behaves differently than the private in languages like Java. I will not write in detail because I have to explain the receiver etc., but for the time being, I can say that even if there is private, the method can be seen in the inheritance destination. So in Java, protected may be closer. [Ruby] The essence of private methods and the benefits of understanding them

By the way, in Ruby, the namespaces of variables and methods are separate, so you can call methods even if you write them without parentheses. The method then returns the result of the last evaluated expression without writing a return. @Variable name is an instance variable. In Ruby, you can tell the type (scope) of a variable by the first character of the variable name.

conditions result
Instance variables "SubClass"
Method instead of instance variable "SubClass"
Private methods instead of instance variables "SubClass"
View code (Ruby)
class SuperClass
  def initialize()
    @instance_variable = "SuperClass"
  end

  def super_class_method
    p @instance_variable
  end
end

class SubClass < SuperClass
  def initialize()
    super()
    @instance_variable = "SubClass"
  end
end

# --------------------------------

class SuperClassGetter
  def instance_variable()
    "SuperClass"
  end

  def super_class_method
    p instance_variable
  end
end

class SubClassGetter < SuperClassGetter
  def instance_variable()
    "SubClass"
  end
end

# --------------------------------

class SuperClassGetterPrivate
  def super_class_method
    p instance_variable
  end

  private

  def instance_variable()
    "SuperClass"
  end
end

class SubClassGetterPrivate < SuperClassGetterPrivate
  private
  
  def instance_variable()
    "SubClass"
  end
end

p '---- SubClass ----'
subc = SubClass.new
subc.super_class_method

p '---- SubClassGetter ----'
subg = SubClassGetter.new
subg.super_class_method

p '---- SubClassGetterPrivate ----'
subgp = SubClassGetterPrivate.new
subgp.super_class_method

PHP

PHP has private, protected, and public like Java. It's basically not in Python, Ruby, or JavaScript! Jealous! But unlike Java, protected instance variables go to read subclasses. That's a move that is in line with other dynamically typed languages.

conditions result
Instance variable is private "SuperClass"
Instance variables are protected "SubClass"
Private methods instead of instance variables "SuperClass"
Protected methods instead of instance variables "SubClass"
View code (PHP)
<?php
function println($message)
{
    echo $message.PHP_EOL;
}

// ----------------------------------------

class SuperClass
{
    private $instanceVariable = "SuperClass";

    public function superClassMethod()
    {
        println($this->instanceVariable);
    }
}

class SubClass extends SuperClass
{
    private $instanceVariable = "SubClass";
}

// ----------------------------------------

class SuperClassProtected
{
    protected $instanceVariable = "SuperClass";

    public function superClassMethod()
    {
        println($this->instanceVariable);
    }
}

class SubClassProtected extends SuperClassProtected
{
    protected $instanceVariable = "SubClass";
}

// ----------------------------------------

class SuperClassGetter
{
    private function instanceVariable()
    {
        return "SuperClass";
    }
    
    public function superClassMethod()
    {
        println($this->instanceVariable());
    }
}

class SubClassGetter extends SuperClassGetter
{
    private function instanceVariable()
    {
        return "SubClass";
    }
}

// ----------------------------------------

class SuperClassGetterProtected
{
    protected function instanceVariable()
    {
        return "SuperClass";
    }
    
    public function superClassMethod()
    {
        println($this->instanceVariable());
    }
}

class SubClassGetterProtected extends SuperClassGetterProtected
{
    protected function instanceVariable()
    {
        return "SubClass";
    }
}

// ----------------------------------------

println("---- SubClass ----");
$sub = new SubClass();
$sub->superClassMethod();

println("---- SubClassProtected ----");
$subp = new SubClassProtected();
$subp->superClassMethod();

println("---- SubClassGetter ----");
$subg = new SubClassGetter();
$subg->superClassMethod();

println("---- SubClassGetterProtected ----");
$subgp = new SubClassGetterProtected();
$subgp->superClassMethod();

JavaScript

The front-end champion. A prototype-based object-oriented language, a language inspired by the programming language Self. Since ES6 and later JavaScript also incorporates class-based writing, it can be inherited by ʻextends`.

conditions result
Instance variables "SubClass"
Instance variables in the old way "SubClass"
An instance variable whose calling method is an arrow function "SubClass"
Arrow function instead of instance variable "SubClass"
View code (JavaScript)
class SuperClass {
  constructor() {
    this.instanceVariable = "SuperClass"
  }

  superClassMethod() {
    console.log(this.instanceVariable)
  }
}

class SubClass extends SuperClass {
  constructor() {
    super()
    this.instanceVariable = "SubClass"
  }
}

// ------------------------

function LegacySuperClass() {
  this.instanceVariable = "SuperClass";
};
LegacySuperClass.prototype.superClassMethod = function() {
  console.log(this.instanceVariable)
}; 

function LegacySubClass() {
  this.instanceVariable = "SubClass";
};
LegacySubClass.prototype = new LegacySuperClass();

// ------------------------

class SuperClassArrow {
  constructor() {
    this.instanceVariable = "SuperClass"
  }

  superClassMethod = () => {
    console.log(this.instanceVariable)
  }
}

class SubClassArrow extends SuperClassArrow {
  constructor() {
    super()
    this.instanceVariable = "SubClass"
  }
}

// ------------------------

class SuperClassGetterArrow {
  instanceVariable = () => {
    return "SuperClass"
  }

  superClassMethod = () => {
    console.log(this.instanceVariable())
  }
}

class SubClassGetterArrow extends SuperClassGetterArrow {
  instanceVariable = () => {
    return "SubClass"
  }
}

// ------------------------

console.log('---- SubClass ----')
const sub = new SubClass()
sub.superClassMethod()

console.log('---- LegacySubClass ----')
var lsub = new LegacySubClass()
lsub.superClassMethod()

console.log('---- SubClassArrow ----')
const suba = new SubClassArrow()
suba.superClassMethod()

console.log('---- SubClassGetterArrow ----')
const subga = new SubClassGetterArrow()
subga.superClassMethod()

TypeScript

It's cool JavaScript that can be statically typed. There are union types, which are similar to the types found in Haskell, which has an advanced type system, and there are conditional types, mapped types, and other expressive types.

In TypeScript, defining a member with the same name as private in a parent class and a child class will result in a compile error. If it is protected, there is no problem. It's the exact opposite of Swift.

conditions result
Instance variable is private Undefinable
Instance variables are protected "SubClass"
Private methods instead of instance variables Undefinable
The instance variable is protected and the calling method is an arrow function "SubClass"
Protected arrow function instead of instance variable "SubClass"
View code (TypeScript)
class SuperClass {
  private readonly instanceVariable: string

  constructor() {
    this.instanceVariable = "Error"
  }

  public superClassMethod() {
    console.log(this.instanceVariable)
  }
}

class SubClass extends SuperClass {
  //When I try to define it with instanceVariable
  // TS2415: Class 'SubClass' incorrectly extends base class 'SuperClass'.
  // private readonly instanceVariable: string

  // constructor() {
  //   super()
  //   this.instanceVariable = "SubClass"
  // }
}

// ------------------------

class SuperClassGetter {
  private instanceVariable() {
    return "Error"
  }

  public superClassMethod() {
    console.log(this.instanceVariable())
  }
}

class SubClassGetter extends SuperClassGetter {
  //When I try to define it with instanceVariable
  // TS2415: Class 'SubClassGetter' incorrectly extends base class 'SuperClassGetter'.
  // Types have separate declarations of a private property 'instanceVariable'.
  // private instanceVariable() {
  //   return "SubClass"
  // }
}

// ------------------------

class SuperClassProtected {
  protected readonly instanceVariable: string

  constructor() {
    this.instanceVariable = "SuperClass"
  }

  public superClassMethod() {
    console.log(this.instanceVariable)
  }
}

class SubClassProtected extends SuperClassProtected {
  protected readonly instanceVariable: string
  
  constructor() {
    super()
    this.instanceVariable = "SubClass"
  }
}

// ------------------------

class SuperClassProtectedGetterArrow {
  protected instanceVariable = () => {
    return "SuperClass"
  }

  public superClassMethod = () => {
    console.log(this.instanceVariable())
  }
}

class SubClassProtectedGetterArrow extends SuperClassProtectedGetterArrow {
  protected instanceVariable = () => {
    return "SubClass"
  }
}

// ------------------------

//Arrow function version
class SuperClassProtectedArrow {
  protected readonly instanceVariable: string

  constructor() {
    this.instanceVariable = "SuperClass"
  }

  public superClassMethod = () => {
    console.log(this.instanceVariable)
  }
}

class SubClassProtectedArrow extends SuperClassProtectedArrow {
  protected readonly instanceVariable: string
  
  constructor() {
    super()
    this.instanceVariable = "SubClass"
  }
}

console.log('---- SubClass ----')
const sub = new SubClass()
sub.superClassMethod()

console.log('---- SubClassGetter ----')
const subg = new SubClassGetter()
subg.superClassMethod()

console.log('---- SubClassProtected ----')
const subp = new SubClassProtected()
subp.superClassMethod()

console.log('---- SubClassProtectedArrow ----')
const subpa = new SubClassProtectedArrow()
subpa.superClassMethod()

console.log('---- SubClassProtectedGetterArrow ----')
const subpga = new SubClassProtectedGetterArrow()
subpga.superClassMethod()

Dart

It's an impressive language that suddenly has a presence since Flutter became popular. You don't write private or public in Dart. You can make it private by adding an underscore to the member name, but it is different from private such as Java because it only makes it invisible from outside the library.

conditions result
Instance variable (with Ansco) "SubClass"
Instance variables "SubClass"
Method instead of instance variable "SubClass"
View code (Dart)
void main() {
  print("---- SubClassPrivate ----");
  final subp = new SubClassPrivate();
  subp.superClassMethod();

  print("---- SubClass ----");
  final sub = new SubClass();
  sub.superClassMethod();

  print("---- SubClassGetter ----");
  final subg = new SubClassGetter();
  subg.superClassMethod();
}

class SuperClassPrivate {
  //If you give an underscore, it becomes Private, but
  //Since private is visible to the same library, it looks normal to subclasses here
  final String _instanceVariable = "SuperClass";

  void superClassMethod() => print(_instanceVariable);
}

class SubClassPrivate extends SuperClassPrivate {
  final String _instanceVariable = "SubClass";
}

// ------------------------------------

class SuperClass {
  final String instanceVariable = "SuperClass";

  void superClassMethod() => print(instanceVariable);
}

class SubClass extends SuperClass {
  final String instanceVariable = "SubClass";
}

// ------------------------------------

class SuperClassGetter {
  String instanceVariable() => "SuperClass";

  void superClassMethod() => print(instanceVariable());
}

class SubClassGetter extends SuperClassGetter {
  String instanceVariable() => "SubClass";
}

Summary

It was surprisingly fun because there were things I didn't know even in a language I was used to to some extent. Some of the examples I wrote for the first time this time, so there is a way to write it like this! Or something wrong! Please comment if you have any.

Overall, I got the impression that in a dynamically typed language, even when a superclass method is called, it first tries to be evaluated in the subclass context. On the other hand, in a statically typed language, it was like, "Because it is a method of a superclass, the basics are evaluated by the superclass. However, if you override it, that is not the case."

The following five were personally impressive.

--C # has a non-overriding qualifier called new --Scala and Kotlin are statically typed languages, but you can override instance variables --Python underscore The two member names were more than just names, they also had an effect. --PHP has a private like Java even though it is a dynamically typed language --TypeScript prevents duplicate private members with the same name from causing an error at compile time and causing unexpected behavior.

Change log

--Fixed an error in the explanation of the Python naming convention. Thank you @shiracamus. --It was pointed out that the word private is not used in Python, so I fixed it. Thank you @Luice.

Recommended Posts