Constructor Parameter vs Member Variable

Jonathan M Davis newsgroup.d at jmdavisprog.com
Tue Dec 5 04:31:28 UTC 2023


On Monday, December 4, 2023 7:41:51 PM MST Christopher Winter via Digitalmars-
d wrote:
> If you have a struct member variable named `a` and a constructor
> for that struct that takes a parameter named `a`, it isn't
> obvious what the usage of `a` in the body refers to.
>
> ```
> import std;
>
> struct F
> {
>      int a;
>      int b;
>
>      this(double a)
>      {
>          writeln(a);
>          a = a;
>      }
> }
>
> void main()
> {
>      scope f = F(15);
>
>      writeln(f.a);
> }
> ```
>
> The behavior is extremely unintutive, and arguably broken, in
> that it a) compiles and b) will print 15 on the first line and 0
> on the second line. Additionally, if you rename the constructor
> parameter to be `c`, then it fails to compile (because you can't
> assign a double to an int).
>
> Is there a way to have the compiler warn or error in this
> situation? Or in general does anyone know ways to avoid the
> ambiguity, other than just being careful with names?

This behavior is actually extremely common in OO programming languages. The
solution to this is to use the this reference when there's any ambiguity.
The more local symbol is always going to win when one symbol shadows
another, and while some kinds of symbol shadowing are disallowed in D,
completely disallowing it can be annoying (e.g. plenty of programmers would
be annoyed if they had to name constructor parameters differently from
member variables when the whole point of the parameter is to assign to the
member variable). So, in your example, you'd do

this(double a)
{
    this.a = cast(int) a;
}

Of course, it's complicated by the fact that you made the parameter double,
and the member variable int, whereas usually, the types would match (so the
cast wouldn't be required), but in general, it's extremely common (both in D
and other OO languages such as C++, Java, etc.) to name parameters to a
constructor with the exact same name as the member variables that they're
intended to be assigned to.

Now, the other solution to this is to name member variables differently from
other variables, and when they're private, this is extremely common
practice, in which case, just looking at the variable name makes it's clear
that you're looking at a private member variable. The most common naming
schemes for such member variables would be to prepend them with an
underscore or to prepend them with m_. e.g.

struct S
{
    private int _a;

    this(int a)
    {
        _a = a;
    }
}

But that sort of thing isn't normally done with public members.

- Jonathan M Davis





More information about the Digitalmars-d mailing list