Jump to page: 1 2
Thread overview
Super easy struct construction question that I'm embarrassed to ask.
Jan 09
Dennis
Jan 13
user1234
Jan 10
An
Jan 13
Dennis
January 09
import std.stdio;

struct Location {
    int r;
    int c;
}

struct Node {
    this(Location locaction, uint f) {
        this.location = location;
        this.f = f;
    }
    Location location;
    uint f;
}

void main() {
    Node n = Node(Location(1,2), 33);
    writeln("n = ", n);
}

---------------------------------------------------

produces:
n = Node(Location(0, 0), 33)
when I expected
n = Node(Location(1, 2), 33)


So structs are value objects (not reference like classes). So it is passed by value.  So a copy of 1 and 2 is made upon entering the constructor this.  But aren't these copies then placed into the Node structure n (for the lifetime of n). So that writeln should produce Location(1, 2), 33.
January 09

On Thursday, 9 January 2025 at 22:01:59 UTC, WhatMeWorry wrote:

>
this(Location locaction, uint f) {
    this.location = location;
    this.f = f;
}

You misspelled the parameter name 'locaction', so your assignment in the constructor is a no-op:

this.location = this.location
January 09
>

You misspelled the parameter name 'locaction', so your assignment in the constructor is a no-op:

this.location = this.location

Thanks. I was starting to question my sanity.

January 10

On Thursday, 9 January 2025 at 22:01:59 UTC, WhatMeWorry wrote:

>

produces:
n = Node(Location(0, 0), 33)
when I expected
n = Node(Location(1, 2), 33)

This is a simple typo (it shouldn't be 1 letter) but the code should be made smarter thanks to the capabilities of D. No more fear of writing like C and getting lost like C++. For example:

struct Location
{
  int x, y;

  auto opBinary(string op = "*")(uint m)
  {
    x *= m;
    y *= m;

    return this;
  }
}

import std.stdio;
void main()
{
  auto loca = Location(1, 2);
  auto node = Node(loca, 33);

  node.writefln!"n = %s";
}

struct Node
{
  uint multiplier;
  Location location;

  this(Location location, uint multiplier)
  {
    this.location = location * multiplier;
    this.multiplier = multiplier;
  }

}

SDB@79

January 10
>

struct Node
{
uint multiplier;
Location location;

this(Location locaction, uint multiplier)
{
this.location = location * multiplier;
this.multiplier = multiplier;
}

}

I appreciate your example of the robustness of D, but if I was to make the same syntax mistake:

this(Location locaction, uint multiplier) // extraneous letter

it returns same error:

n = Node(33, Location(0, 0))

I guess there is no fix for stupidity on my part. :)

January 10

On Thursday, 9 January 2025 at 22:08:31 UTC, Dennis wrote:

>

On Thursday, 9 January 2025 at 22:01:59 UTC, WhatMeWorry wrote:

>
this(Location locaction, uint f) {
    this.location = location;
    this.f = f;
}

You misspelled the parameter name 'locaction', so your assignment in the constructor is a no-op:

this.location = this.location

If the compiler flags this as an warning -> he probably notice the problem
Lag of error/warn/hint for such case is not helping
Happy coding

January 13

On Thursday, 9 January 2025 at 22:08:31 UTC, Dennis wrote:

>

On Thursday, 9 January 2025 at 22:01:59 UTC, WhatMeWorry wrote:

>
this(Location locaction, uint f) {
    this.location = location;
    this.f = f;
}

You misspelled the parameter name 'locaction', so your assignment in the constructor is a no-op:

this.location = this.location

Which is why languages like Zig disallow such code ... unused variables must be identified as such.

January 12
On Mon, Jan 13, 2025 at 04:05:25AM +0000, Jim Balter via Digitalmars-d-learn wrote:
> On Thursday, 9 January 2025 at 22:08:31 UTC, Dennis wrote:
> > On Thursday, 9 January 2025 at 22:01:59 UTC, WhatMeWorry wrote:
> > >     this(Location locaction, uint f) {
> > >         this.location = location;
> > >         this.f = f;
> > >     }
> > 
> > 
> > You misspelled the parameter name 'locaction', so your assignment in the constructor is a no-op:
> > 
> > ```
> > this.location = this.location
> > ```
> 
> Which is why languages like Zig disallow such code ... unused variables must be identified as such.

I wish there was some kind of syntactic sugar for assigning ctor parameters to class members. This kind of boilerplate happens quite a lot on OO-style code, and is a common place for typos and other such careless mistakes, because it's just so repetitious that you don't really pay attention to it when writing it.

Especially bad is naming ctor parameters with exactly the same identifier as the class member, then it becomes non-obvious whether occurrences of that identifier refers to the parameter or to the class member.  A common convention is to append or prepend `_` to one of them, but even that is easily overlooked, and a single-chararacter typo reverts back to the same problem.  And it still doesn't address the main issue, which is the blatant violation of DRY.

I've seen some D users use mixins to automate away the boilerplate, but TBH it looks kinda messy, and isn't really conducive to the cases where most ctor arguments are to be copied but one or two must be specially treated.  Some kind of default ctor mechanism that still allows for custom code where needed, would be really nice.


T

-- 
Without outlines, life would be pointless.
January 13

On Thursday, 9 January 2025 at 23:44:52 UTC, WhatMeWorry wrote:

> >

You misspelled the parameter name 'locaction', so your assignment in the constructor is a no-op:

this.location = this.location

Thanks. I was starting to question my sanity.

That error is so classic that eventually a well know linter detects it: https://pvs-studio.com/en/docs/warnings/v3196/

Sure that's not a D linter however.

January 13
On 1/12/25 8:55 PM, H. S. Teoh wrote:

> I wish there was some kind of syntactic sugar for assigning ctor
> parameters to class members.

Amen. Dart provides some help. It's under Generative Constructors here:

  https://dart.dev/language/constructors

class Point {
  // Instance variables to hold the coordinates of the point.
  double x;
  double y;

  // Generative constructor with initializing formal parameters:
  Point(this.x, this.y);
}

The following comment under the next section hints at what happens when a constructor body is provided:

  // Sets the x and y instance variables
  // before the constructor body runs.

Ali

« First   ‹ Prev
1 2