Skip to content

Commit 0f0a49d

Browse files
authored
Merge pull request #2329 from WalterBright/class-ctor
improve class construction and field initialization verbiage merged-on-behalf-of: Walter Bright <WalterBright@users.noreply.github.com>
2 parents 7112d4d + 42927a9 commit 0f0a49d

File tree

1 file changed

+76
-52
lines changed

1 file changed

+76
-52
lines changed

spec/class.dd

Lines changed: 76 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -299,16 +299,12 @@ $(GNAME Constructor):
299299
$(GLINK2 template, ConstructorTemplate)
300300
)
301301

302-
$(P Members are always initialized to the
302+
$(P Fields are by default initialized to the
303303
$(LNAME2 class-default-initializer, default initializer)
304-
for their type, which is usually 0 for integer types and
305-
NAN for floating point types.
306-
This eliminates an entire
307-
class of obscure problems that come from
308-
neglecting to initialize a member in one of the constructors.
309-
In the class definition,
310-
there can be a static initializer to be
311-
used instead of the default:
304+
for their type (usually 0 for integer types and
305+
NAN for floating point types).
306+
If the field declaration has an optional $(GLINK2 declaration, Initializer)
307+
that will be used instead of the default.
312308
)
313309
------
314310
class Abc
@@ -319,7 +315,9 @@ $(GNAME Constructor):
319315
}
320316
------
321317

322-
$(P This static initialization is done before any constructors are
318+
$(P The $(I Initializer) is evaluated at compile time.)
319+
320+
$(P This initialization is done before any constructors are
323321
called.)
324322

325323
$(P Constructors are defined with a function name of $(D this)
@@ -355,9 +353,9 @@ $(GNAME Constructor):
355353
}
356354
------
357355

358-
$(P Constructors can also call other constructors for the same class
356+
$(P Constructors can call other constructors for the same class
359357
in order to share common initializations
360-
$(LNAME2 delegating-constructors, (this is called delegating constructors)):
358+
(this is called a $(LNAME2 delegating-constructors, delegating constructor)):
361359
)
362360

363361
------
@@ -370,7 +368,7 @@ $(GNAME Constructor):
370368
}
371369
this(int i)
372370
{
373-
$(CODE_HIGHLIGHT this)();
371+
$(CODE_HIGHLIGHT this)(); // delegating constructor call
374372
j = i;
375373
}
376374
}
@@ -388,23 +386,12 @@ $(GNAME Constructor):
388386
this() { }
389387
------
390388

391-
$(P Class object construction is very flexible, but some restrictions
392-
apply:)
389+
$(P The following restrictions apply to class construction:)
393390

394391
$(OL
395-
$(LI It is illegal for constructors to mutually call each other,
396-
although the compiler is not required to detect it. It will result
397-
in undefined behavior.
398-
399-
------
400-
this() { this(1); }
401-
this(int i) { this(); } // illegal, cyclic constructor calls
402-
------
403-
)
404-
405-
$(LI If any constructor call appears inside a constructor, any
406-
path through the constructor must make exactly one constructor
407-
call:
392+
$(LI If a constructor's code contains a delegate constructor call, all
393+
possible execution paths through the constructor must make exactly one
394+
delegate constructor call:
408395

409396
------
410397
this() { a || super(); } // illegal
@@ -422,13 +409,12 @@ $(GNAME Constructor):
422409
)
423410

424411
$(LI It is illegal to refer to $(D this) implicitly or explicitly
425-
prior to making a constructor call.)
412+
prior to making a delegate constructor call.)
426413

427-
$(LI Constructor calls cannot appear after labels (in order to make
428-
it easy to check for the previous conditions in the presence of goto's).)
414+
$(LI Delegate constructor calls cannot appear after labels.)
429415
)
430416

431-
$(P Instances of class objects are created with $(I NewExpression)s:)
417+
$(P Instances of class objects are created with a $(GLINK2 expression, NewExpression):)
432418

433419
------
434420
A a = new A(3);
@@ -439,27 +425,30 @@ $(GNAME Constructor):
439425
$(OL
440426
$(LI Storage is allocated for the object.
441427
If this fails, rather than return $(D null), an
442-
$(D OutOfMemoryError) is thrown.
428+
$(LINK2 $(ROOT_DIR)library/core/exception/out_of_memory_error.html, OutOfMemoryError) is thrown.
443429
Thus, tedious checks for null references are unnecessary.
444430
)
445431

446432
$(LI The raw data is statically initialized using the values provided
447433
in the class definition.
448434
The pointer to the vtbl[] (the array of pointers to virtual functions)
449435
is assigned.
450-
This ensures that constructors are
436+
Constructors are
451437
passed fully formed objects for which virtual functions can be called.
452438
This operation is equivalent to doing a memory copy of a static
453-
version of the object onto the newly allocated one,
454-
although more advanced compilers
455-
may be able to optimize much of this away.
439+
version of the object onto the newly allocated one.
456440
)
457441

458442
$(LI If there is a constructor defined for the class,
459443
the constructor matching the
460444
argument list is called.
461445
)
462446

447+
$(LI If a delegating constructor is not called, a call to the base
448+
class's default constructor is issued.)
449+
450+
$(LI The body of the constructor is executed.)
451+
463452
$(LI If class invariant checking is turned on, the class invariant
464453
is called at the end of the constructor.
465454
)
@@ -503,7 +492,7 @@ $(GNAME Constructor):
503492
immutable i = new immutable C();
504493
------
505494

506-
$(P If the constructor can create unique object (e.g. if it is pure),
495+
$(P If the constructor can create a unique object (e.g. if it is `pure`),
507496
the object can be implicitly convertible to any qualifiers.
508497
)
509498
------
@@ -512,15 +501,14 @@ $(GNAME Constructor):
512501
this() pure;
513502
// Based on the definition, this creates a mutable object. But the
514503
// created object cannot contain any mutable global data.
515-
// Then compiler can guarantee that the created object is unique.
504+
// Therefore the created object is unique.
516505

517506
this(int[] arr) immutable pure;
518507
// Based on the definition, this creates an immutable object. But
519508
// the argument int[] never appears in the created object so it
520509
// isn't implicitly convertible to immutable. Also, it cannot store
521510
// any immutable global data.
522-
// Therefore the compiler can guarantee that the created object is
523-
// unique.
511+
// Therefore the created object is unique.
524512
}
525513

526514
immutable i = new immutable C(); // this() pure is called
@@ -530,42 +518,43 @@ $(GNAME Constructor):
530518

531519
$(H2 $(LNAME2 field-init, Field initialization inside constructor))
532520

533-
$(P Inside constructor, the first instance field assignment is specially
534-
handled for its initialization.
535-
)
521+
$(P In a constructor body, the first instance of field assignment is
522+
its initialization.
523+
)
536524

537525
------
538526
class C
539527
{
540528
int num;
541529
this()
542530
{
543-
num = 1; // initialize
531+
num = 1; // initialization
544532
num = 2; // assignment
545533
}
546534
}
547535
------
548536

549-
$(P If the field type has opAssign method, it won't be used for initialization.)
537+
$(P If the field type has an $(LINK2 operatoroverloading.html#assignment, `opAssign`)
538+
method, it will not be used for initialization.)
550539

551540
------
552541
struct A
553542
{
554543
this(int n) {}
555-
void opAssign(A rhs) {}
544+
void $(CODE_HIGHLIGHT opAssign)(A rhs) {}
556545
}
557546
class C
558547
{
559548
A val;
560549
this()
561550
{
562-
val = A(1); // A(1) is moved in this.val for initializing
551+
val = A(1); // val is initialized to the value of A(1)
563552
val = A(2); // rewritten to val.opAssign(A(2))
564553
}
565554
}
566555
------
567556

568-
$(P If the field type is not modifiable, multiple initialization will be rejected.)
557+
$(P If the field type is not mutable, multiple initialization will be rejected.)
569558

570559
------
571560
class C
@@ -579,9 +568,30 @@ $(H2 $(LNAME2 field-init, Field initialization inside constructor))
579568
}
580569
------
581570

582-
$(P If the assignment expression for the field initialization may be invoked
583-
multiple times, it would also be rejected.
584-
)
571+
$(P If the field is initialized on one path, it must be initialized on all paths.)
572+
---
573+
class C
574+
{
575+
immutable int num;
576+
immutable int ber;
577+
this(int i)
578+
{
579+
if (i)
580+
num = 3; // initialization
581+
else
582+
num = 4; // initialization
583+
}
584+
this(long j)
585+
{
586+
j ? (num = 3) : (num = 4); // ok
587+
j || (ber = 3); // error, intialized on only one path
588+
j && (ber = 3); // error, intialized on only one path
589+
}
590+
}
591+
---
592+
593+
$(P A field initialization may not appear in a loop or after
594+
a label.)
585595

586596
------
587597
class C
@@ -603,6 +613,20 @@ $(H2 $(LNAME2 field-init, Field initialization inside constructor))
603613
}
604614
------
605615

616+
$(P If a field's type has disabled default construction, then it must be initialized
617+
in the constructor.)
618+
---
619+
struct S { int y; @disable this(); }
620+
621+
class C
622+
{
623+
S s;
624+
this(S t) { s = t; } // ok
625+
this(int i) { this(); } // ok
626+
this() { } // error, s not initialized
627+
}
628+
---
629+
606630
$(H2 $(LNAME2 destructors, Destructors))
607631

608632
$(GRAMMAR

0 commit comments

Comments
 (0)