-
-
Notifications
You must be signed in to change notification settings - Fork 377
/
Copy pathfunction.dd
4150 lines (3314 loc) · 122 KB
/
function.dd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
Ddoc
$(SPEC_S Functions,
$(HEADERNAV_TOC)
$(H2 $(LNAME2 grammar, Grammar))
$(H3 Function declaration)
$(GRAMMAR
$(GNAME FuncDeclaration):
$(GLINK2 declaration, StorageClasses)$(OPT) $(GLINK2 type, BasicType) $(GLINK FuncDeclarator) $(GLINK FunctionBody)
$(GLINK AutoFuncDeclaration)
$(GNAME AutoFuncDeclaration):
$(GLINK2 declaration, StorageClasses) $(GLINK_LEX Identifier) $(GLINK FuncDeclaratorSuffix) $(GLINK FunctionBody)
$(GNAME FuncDeclarator):
$(GLINK2 type, TypeSuffixes)$(OPT) $(GLINK_LEX Identifier) $(GLINK FuncDeclaratorSuffix)
$(GNAME FuncDeclaratorSuffix):
$(GLINK Parameters) $(GLINK MemberFunctionAttributes)$(OPT)
$(GLINK2 template, TemplateParameters) $(GLINK Parameters) $(GLINK MemberFunctionAttributes)$(OPT) $(GLINK2 template, Constraint)$(OPT)
)
$(H3 Parameters)
$(GRAMMAR
$(GNAME Parameters):
$(D $(LPAREN)) $(GLINK ParameterList)$(OPT) $(D $(RPAREN))
$(GNAME ParameterList):
$(GLINK Parameter)
$(GLINK Parameter) $(D ,)
$(GLINK Parameter) $(D ,) $(GSELF ParameterList)
$(GLINK VariadicArgumentsAttributes)$(OPT) $(D ...)
$(GNAME Parameter):
$(GLINK ParameterAttributes)$(OPT) $(GLINK2 type, BasicType) $(GLINK2 declaration, Declarator)
$(GLINK ParameterAttributes)$(OPT) $(GLINK2 type, BasicType) $(GLINK2 declaration, Declarator) $(D ...)
$(GLINK ParameterAttributes)$(OPT) $(GLINK2 type, BasicType) $(GLINK2 declaration, Declarator) $(D =) $(ASSIGNEXPRESSION)
$(GLINK ParameterAttributes)$(OPT) $(GLINK2 type, Type)
$(GLINK ParameterAttributes)$(OPT) $(GLINK2 type, Type) $(D ...)
$(GLINK ParameterAttributes)$(OPT) $(GLINK2 type, Type) $(D =) $(ASSIGNEXPRESSION)
$(GNAME ParameterAttributes):
$(GLINK ParameterStorageClass)
$(GLINK2 attribute, UserDefinedAttribute)
$(GSELF ParameterAttributes) $(GLINK ParameterStorageClass)
$(GSELF ParameterAttributes) $(GLINK2 attribute, UserDefinedAttribute)
$(GNAME ParameterStorageClass):
$(D auto)
$(GLINK2 type, TypeCtor)
$(D final)
$(D in)
$(D lazy)
$(D out)
$(D ref)
$(D return)
$(D scope)
$(GNAME VariadicArgumentsAttributes):
$(GLINK VariadicArgumentsAttribute)
$(GLINK VariadicArgumentsAttribute) $(GSELF VariadicArgumentsAttributes)
$(GNAME VariadicArgumentsAttribute):
$(D const)
$(D immutable)
$(D return)
$(D scope)
$(D shared)
)
$(NOTE In D2, declaring a parameter `final` is a semantic error, but not a parse error.)
$(P See also: $(RELATIVE_LINK2 param-storage, parameter storage classes).)
$(H3 Function attributes)
$(GRAMMAR
$(GNAME FunctionAttributes):
$(GLINK FunctionAttribute)
$(GLINK FunctionAttribute) $(GSELF FunctionAttributes)
$(GNAME FunctionAttribute):
$(GLINK2 attribute, FunctionAttributeKwd)
$(GLINK2 attribute, Property)
$(GLINK2 attribute, AtAttribute)
$(GNAME MemberFunctionAttributes):
$(GLINK MemberFunctionAttribute)
$(GLINK MemberFunctionAttribute) $(GSELF MemberFunctionAttributes)
$(GNAME MemberFunctionAttribute):
$(D const)
$(D immutable)
$(D inout)
$(D return)
$(D scope)
$(D shared)
$(GLINK FunctionAttribute)
)
$(H3 $(LNAME2 function-bodies, Function Bodies))
$(GRAMMAR
$(GNAME FunctionBody):
$(GLINK SpecifiedFunctionBody)
$(GLINK ShortenedFunctionBody)
$(GLINK MissingFunctionBody)
$(GNAME SpecifiedFunctionBody):
$(D do)$(OPT) $(GLINK2 statement, BlockStatement)
$(GLINK FunctionContracts)$(OPT) $(GLINK InOutContractExpression) $(D do)$(OPT) $(GLINK2 statement, BlockStatement)
$(GLINK FunctionContracts)$(OPT) $(GLINK InOutStatement) $(D do) $(GLINK2 statement, BlockStatement)
$(GNAME ShortenedFunctionBody):
$(GLINK InOutContractExpressions)$(OPT) $(D =>) $(GLINK2 expression, AssignExpression) $(D ;)
)
$(P Examples:)
---
int hasSpecifiedBody() { return 1; }
int hasShortenedBody() => 1; // equivalent
---
$(LEGACY_LNAME2 FunctionLiteralBody)
$(P The *ShortenedFunctionBody* form implies a
$(DDSUBLINK spec/statement, ReturnStatement, return statement).
This syntax also applies for $(DDSUBLINK spec/expression, function_literals, function literals).)
$(P $(B Note:) The *ShortenedFunctionBody* form requires the `-preview=shortenedMethods`
command-line switch, which is available starting in v2.096.0.)
$(H3 $(LNAME2 function-declarations, Functions without Bodies))
$(GRAMMAR
$(GNAME MissingFunctionBody):
$(D ;)
$(GLINK FunctionContracts)$(OPT) $(GLINK InOutContractExpression) $(D ;)
$(GLINK FunctionContracts)$(OPT) $(GLINK InOutStatement)
)
$(P Functions without bodies:)
---
int foo();
---
$(P that are not declared as $(D abstract) are expected to have their implementations
elsewhere, and that implementation will be provided at the link step.
This enables an implementation of a function to be completely hidden from the user
of it, and the implementation may be in another language such as C, assembler, etc.
)
$(H2 $(LNAME2 contracts, Function Contracts))
$(GRAMMAR
$(GNAME FunctionContracts):
$(GLINK FunctionContract)
$(GLINK FunctionContract) $(GSELF FunctionContracts)
$(GNAME FunctionContract):
$(GLINK InOutContractExpression)
$(GLINK InOutStatement)
$(GNAME InOutContractExpressions):
$(GLINK InOutContractExpression)
$(GLINK InOutContractExpression) $(GSELF InOutContractExpressions)
$(GNAME InOutContractExpression):
$(GLINK InContractExpression)
$(GLINK OutContractExpression)
$(GNAME InOutStatement):
$(GLINK InStatement)
$(GLINK OutStatement)
$(GNAME InContractExpression):
$(D in $(LPAREN)) $(GLINK2 expression, AssertArguments) $(D $(RPAREN))
$(GNAME OutContractExpression):
$(D out $(LPAREN) ;) $(GLINK2 expression, AssertArguments) $(D $(RPAREN))
$(D out $(LPAREN)) $(GLINK_LEX Identifier) $(D ;) $(GLINK2 expression, AssertArguments) $(D $(RPAREN))
$(GNAME InStatement):
$(D in) $(GLINK2 statement, BlockStatement)
$(GNAME OutStatement):
$(D out) $(GLINK2 statement, BlockStatement)
$(D out) $(D $(LPAREN)) $(GLINK_LEX Identifier) $(D $(RPAREN)) $(GLINK2 statement, BlockStatement)
)
$(P Function Contracts specify the preconditions and postconditions of a function.
They are used in $(LINK2 contracts.html, Contract Programming).
)
$(P Preconditions and postconditions do not affect the type of the function.)
$(H3 $(LNAME2 preconditions, Preconditions))
$(P An $(GLINK InContractExpression) is a precondition.)
$(P The first $(GLINK2 expression, AssignExpression) of the $(GLINK2 expression, AssertArguments)
must evaluate to true. If it does not, the precondition has failed.)
$(P The second $(I AssignExpression), if present, must be implicitly convertible to type `const(char)[]`.
)
$(P An $(GLINK InStatement) is also a precondition. Any $(GLINK2 expression, AssertExpression) appearing
in an $(I InStatement) will be an $(I InContractExpression).
)
$(P Preconditions must semantically be satisfied before the function starts executing.
If it is not, the program enters an $(I Invalid State).
)
$(IMPLEMENTATION_DEFINED Whether the preconditions are actually run or not is implementation defined.
This is usually selectable with a compiler switch.
Its behavior upon precondition failure is also usually selectable with a compiler switch.
One option is to throw an `AssertError` with a message consisting of the optional second
$(I AssignExpression).
)
$(BEST_PRACTICE Use preconditions to validate that input arguments have values that are
expected by the function.)
$(BEST_PRACTICE Since preconditions may or may not be actually checked at runtime, avoid
using preconditions that have side effects.)
$(P The expression form is:)
---
in (expression)
in (expression, "failure string")
{
...function body...
}
---
$(P The block statement form is:)
---
in
{
...contract preconditions...
}
do
{
...function body...
}
---
$(H3 $(LNAME2 postconditions, Postconditions))
$(P An $(GLINK OutContractExpression) is a postcondition.)
$(P The first $(GLINK2 expression, AssignExpression) of the $(GLINK2 expression, AssertArguments)
must evaluate to true. If it does not, the postcondition has failed.)
$(P The second $(I AssignExpression), if present, must be implicitly convertible to type `const(char)[]`.
)
$(P An $(GLINK OutStatement) is also a postcondition. Any $(GLINK2 expression, AssertExpression) appearing
in an $(I OutStatement) will be an $(I OutContractExpression).
)
$(P Postconditions must semantically be satisfied after the function finishes executing.
If it is not, the program enters an $(I Invalid State).
)
$(IMPLEMENTATION_DEFINED Whether the postconditions are actually run or not is implementation defined.
This is usually selectable with a compiler switch.
Its behavior upon postcondition failure is also usually selectable with a compiler switch.
One option is to throw an `AssertError` with a message consisting of the optional second
$(I AssignExpression).
)
$(BEST_PRACTICE Use postconditions to validate that the input arguments and return value have values that are
expected by the function.)
$(BEST_PRACTICE Since postconditions may or may not be actually checked at runtime, avoid
using postconditions that have side effects.)
$(P The expression form is:)
---
out (identifier; expression)
out (identifier; expression, "failure string")
out (; expression)
out (; expression, "failure string")
{
...function body...
}
---
$(P The block statement form is:)
---
out
{
...contract postconditions...
}
out (identifier)
{
...contract postconditions...
}
do
{
...function body...
}
---
$(P The optional identifier in either type of postcondition is set to the return value
of the function, and can be accessed from within the postcondition.)
$(H3 Example)
---
int fun(ref int a, int b)
in (a > 0)
in (b >= 0, "b cannot be negative!")
out (r; r > 0, "return must be positive")
out (; a != 0)
{
// function body
}
---
---
int fun(ref int a, int b)
in
{
assert(a > 0);
assert(b >= 0, "b cannot be negative!");
}
out (r)
{
assert(r > 0, "return must be positive");
assert(a != 0);
}
do
{
// function body
}
---
$(P The two functions are identical semantically.)
$(H3 $(LNAME2 in_out_inheritance, In, Out and Inheritance))
$(P If a function in a derived class overrides a function from its
super class, then only the preconditions of one of the
function and its overridden functions
must be satisfied.
Overriding
functions then becomes a process of $(I loosening) the preconditions.
)
$(P A function without preconditions means its precondition is always
satisfied.
Therefore if any
function in an inheritance hierarchy has no preconditions,
then any preconditions on functions overriding it have no meaningful
effect.
)
$(P Conversely, all of the postconditions of the function and its
overridden functions must to be satisfied.
Adding overriding functions then becomes a processes of $(I tightening) the
postconditions.
)
$(H2 $(LNAME2 function-return-values, Function Return Values))
$(P At least one $(DDSUBLINK spec/statement, return-statement, return statement)
is required if the function specifies a return type that is not void,
unless:)
$(UL
$(LI the function executes an infinite loop)
$(LI the function executes an `assert(0)` statement)
$(LI the function evaluates an expression of type
$(DDSUBLINK spec/type, noreturn, `noreturn`))
$(LI the function contains inline assembler code)
)
$(P Function return values not marked as $(RELATIVE_LINK2 ref-functions, `ref`)
are considered to be rvalues.
This means they cannot be passed by reference to other functions.
)
$(H2 $(LNAME2 pure-functions, Pure Functions))
$(P Pure functions are annotated with the `pure` attribute.
Pure functions cannot directly access global or static
mutable state.
Pure functions can only call pure functions.)
$(P Pure functions can:)
$(UL
$(LI Modify the local state of the function.)
$(LI Throw exceptions.)
)
---
int x;
immutable int y;
const int* pz;
pure int foo(int i)
{
i++; // ok, modifying local state
x = i; // error, modifying global state
i = x; // error, reading mutable global state
i = y; // ok, reading immutable global state
i = *pz; // error, reading const global state
throw new Exception("failed"); // ok
}
---
$(P A pure function can override an impure function,
but cannot be overridden by an impure function.
I.e. it is covariant with an impure function.
)
$(P A $(I weakly pure function) has parameters with mutable indirections.
Program state can be modified transitively through the matching
argument.
)
$(SPEC_RUNNABLE_EXAMPLE_RUN
---
pure size_t foo(int[] arr)
{
arr[] += 1;
return arr.length;
}
int[] a = [1, 2, 3];
foo(a);
assert(a == [2, 3, 4]);
---
)
$(P A $(I strongly pure function) has no parameters with mutable indirections
and cannot modify any program state external to the function.
)
---
struct S { double x; }
pure int foo(immutable(int)[] arr, int num, S val)
{
//arr[num] = 1; // compile error
num = 2; // has no side effect to the caller side
val.x = 3.14; // ditto
return arr.length;
}
---
$(P A strongly pure function can call a weakly pure function.)
$(H3 $(LNAME2 pure-special-cases, Special Cases))
$(P A pure function can:)
$(UL
$(LI read and write the floating point exception flags)
$(LI read and write the floating point mode flags, as long as those
flags are restored to their initial state upon function entry)
)
$(UNDEFINED_BEHAVIOR occurs if these flags are not restored to their
initial state upon function exit. It is the programmer's responsibility
to ensure this. Setting these flags is not allowed in `@safe` code.)
$(P A pure function can perform impure operations in statements that are in a
$(GLINK2 version, ConditionalStatement)
controlled by a $(GLINK2 version, DebugCondition).
)
$(BEST_PRACTICE this relaxation of purity checks in *DebugCondition*s is
intended solely to make debugging programs easier.)
---
pure int foo(int i)
{
debug writeln("i = ", i); // ok, impure code allowed in debug statement
...
}
---
$(P $(RELATIVE_LINK2 nested, Nested functions) inside a pure function are implicitly marked as pure.)
---
pure int foo(int x, immutable int y)
{
int bar()
// implicitly marked as pure, to be "weakly pure"
// since hidden context pointer to foo stack context is mutable
{
x = 10; // can access states in enclosing scope
// through the mutable context pointer
return x;
}
pragma(msg, typeof(&bar)); // int delegate() pure
int baz() immutable
// qualifies hidden context pointer with immutable,
// and has no other parameters, therefore "strongly pure"
{
//return x; // error, cannot access mutable data
// through the immutable context pointer
return y; // ok
}
// can call pure nested functions
return bar() + baz();
}
---
$(H3 $(LNAME2 pure-factory-functions, Pure Factory Functions))
$(P A $(I pure factory function) is a strongly pure function
that returns a result that has mutable indirections.
All mutable
memory returned by the call cannot be referenced by any other part of the
program, i.e. it is newly allocated by the function.
The mutable
references of the result similarly cannot refer to any object that
existed before the function call.
This allows the result to be implicitly cast to any qualifier.
For example:)
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
struct List { int payload; List* next; }
pure List* make(int a, int b)
{
auto result = new List(a, null);
result.next = new List(b, result);
return result;
}
void main()
{
auto list = make(1, 2);
pragma(msg, typeof(list)); // List*
immutable ilist = make(1, 2);
pragma(msg, typeof(ilist)); // immutable List*
pragma(msg, typeof(ilist.next)); // immutable List*
}
---
)
$(P All references in `make`'s result refer to `List`
objects created by `make`, and no other part of the program refers to
any of these objects. Hence the result can initialize an immutable
variable.)
$(P This does not affect any *Exception* or *Error* thrown from the function.
)
$(H3 $(LNAME2 pure-optimization, Optimization))
$(IMPLEMENTATION_DEFINED An implementation may assume that a strongly pure
function that returns a result
without mutable indirections will have the same effect for all invocations
with equivalent arguments. It is allowed to memoize the result of the
function under the assumption that equivalent parameters always produce
equivalent results.)
$(P
A strongly pure function may still have behavior
inconsistent with memoization by e.g. using `cast`s or by changing behavior
depending on the address of its parameters. An implementation is currently
not required to enforce validity of memoization in all cases.
If a strongly pure function throws an *Exception* or an *Error*, the
assumptions related to memoization do not carry to the thrown
exception.)
$(P Pure destructors do not benefit of special elision.)
$(H2 $(LNAME2 nothrow-functions, Nothrow Functions))
$(P Nothrow functions can only throw exceptions derived
from $(LINK2 https://dlang.org/phobos/object.html#.Error, $(D class Error)).
)
$(P Nothrow functions are covariant with throwing ones.)
$(H2 $(LNAME2 ref-functions, Ref Functions))
$(P Ref functions allow functions to return by reference,
meaning that the return value must be an lvalue, and
the lvalue is returned, not the rvalue.
)
---
ref int foo()
{
auto p = new int(2);
return *p;
}
...
int i = foo(); // i is set to 2
foo() = 3; // reference returns can be lvalues
---
$(P Returning a reference to an expired function context is not allowed.
This includes local variables, temporaries and parameters that are part
of an expired function context.
)
---
ref int sun()
{
int i;
return i; // error, escaping a reference to local variable i
}
---
$(P A `ref` parameter may not be returned by `ref`.)
---
ref int moon(ref int i)
{
return i; // error
}
---
$(H2 $(LNAME2 auto-functions, Auto Functions))
$(P Auto functions have their return type inferred from any
$(GLINK2 statement, ReturnStatement)s in the function body.
)
$(P An auto function is declared without a return type.
If it does not already have a storage class, use the
$(D_KEYWORD auto) storage class.
)
$(P If there are multiple $(I ReturnStatement)s, the types
of them must be implicitly convertible to a common type.
If there are no $(I ReturnStatement)s, the return type is inferred
to be $(D_KEYWORD void).)
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
auto foo(int x) { return x + 3; } // inferred to be int
auto bar(int x) { return x; return 2.5; } // inferred to be double
---
)
$(H2 $(LNAME2 auto-ref-functions, Auto Ref Functions))
$(P Auto ref functions infer their return type just as
$(RELATIVE_LINK2 auto-functions, auto functions) do.
In addition, they become $(RELATIVE_LINK2 ref-functions, ref functions)
if all return expressions are lvalues,
and it would not be a reference to a local or a parameter.)
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
auto ref f1(int x) { return x; } // value return
auto ref f2() { return 3; } // value return
auto ref f3(ref int x) { return x; } // ref return
auto ref f4(out int x) { return x; } // ref return
auto ref f5() { static int x; return x; } // ref return
---
)
$(P The ref-ness of a function is determined from all
$(GLINK2 statement, ReturnStatement)s in the function body:)
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
auto ref f1(ref int x) { return 3; return x; } // ok, value return
auto ref f2(ref int x) { return x; return 3; } // ok, value return
auto ref f3(ref int x, ref double y)
{
return x; return y;
// The return type is deduced to double, but cast(double)x is not an lvalue,
// then become a value return.
}
---
)
$(P Auto ref function can have explicit return type.)
---
auto ref int (ref int x) { return x; } // ok, ref return
auto ref int foo(double x) { return x; } // error, cannot convert double to int
---
$(H2 $(LNAME2 inout-functions, Inout Functions))
$(P For extensive information see $(DDSUBLINK spec/const3, inout, $(D inout) type qualifier).)
$(H2 $(LNAME2 optional-parenthesis, Optional Parentheses))
$(P If a function call passes no explicit argument, i.e. it would syntactically use $(D ()), then these parentheses
may be omitted, similar to a getter invocation of a
$(RELATIVE_LINK2 property-functions, property function).
A $(RELATIVE_LINK2 pseudo-member, UFCS) call can also omit empty parentheses.
)
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
void foo() {} // no arguments
void fun(int x = 10) {}
void bar(int[] arr) {}
void main()
{
foo(); // OK
foo; // also OK
fun; // OK
int[] arr;
arr.bar(); // UFCS call
arr.bar; // also OK
}
---
)
$(P Due to ambiguity, parentheses are required to call a delegate or a function pointer:)
---
void main()
{
int function() fp;
assert(fp == 6); // Error, incompatible types int function() and int
assert(*fp == 6); // Error, incompatible types int() and int
int delegate() dg;
assert(dg == 6); // Error, incompatible types int delegate() and int
}
---
$(P If a function returns a delegate or a function pointer, any parentheses
apply first to the function call, not the result. Two sets of parentheses are required
to call the result directly:
)
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
int getNum() { return 6; }
int function() getFunc() { return &getNum; }
void main()
{
int function() fp;
fp = getFunc; // implicit call
assert(fp() == 6);
fp = getFunc(); // explicit call
assert(fp() == 6);
int x = getFunc()();
assert(x == 6);
}
---
)
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
struct S
{
int getNum() { return 6; }
int delegate() getDel() return { return &getNum; }
}
void main()
{
S s;
int delegate() dg;
dg = s.getDel; // implicit call
assert(dg() == 6);
dg = s.getDel(); // explicit call
assert(dg() == 6);
int y = s.getDel()();
assert(y == 6);
}
---
)
$(H2 $(LNAME2 property-functions, Property Functions))
$(P WARNING: The definition and usefulness of property functions is being reviewed, and the implementation
is currently incomplete. Using property functions is not recommended until the definition is
more certain and implementation more mature.)
$(P Properties are functions that can be syntactically treated
as if they were fields or variables. Properties can be read from or written to.
A property is read by calling a method or function with no arguments;
a property is written by calling a method or function with its argument
being the value it is set to.
)
$(P Simple getter and setter properties can be written using $(RELATIVE_LINK2 pseudo-member, UFCS).
These can be enhanced with the additon of the $(D @property) attribute to the function, which
adds the following behaviors:
)
$(UL
$(LI $(D @property) functions cannot be overloaded with non-$(D @property) functions with the same name.)
$(LI $(D @property) functions can only have zero, one or two parameters.)
$(LI $(D @property) functions cannot have variadic parameters.)
$(LI For the expression $(D typeof(exp)) where $(D exp) is an $(D @property) function,
the type is the return type of the function, rather than the type of the function.)
$(LI For the expression $(D __traits(compiles, exp)) where $(D exp) is an $(D @property) function,
a further check is made to see if the function can be called.)
$(LI $(D @property) are mangled differently, meaning that $(D @property) must be consistently
used across different compilation units.)
$(LI The ObjectiveC interface recognizes $(D @property) setter functions as special and modifies
them accordingly.)
)
$(P A simple property would be:)
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
struct Foo
{
@property int data() { return m_data; } // read property
@property int data(int value) { return m_data = value; } // write property
private:
int m_data;
}
---
)
$(P To use it:)
---
int test()
{
Foo f;
f.data = 3; // same as f.data(3);
return f.data + 3; // same as return f.data() + 3;
}
---
$(P The absence of a read method means that the property is write-only.
The absence of a write method means that the property is read-only.
Multiple write methods can exist; the correct one is selected using
the usual function overloading rules.
)
$(P In all the other respects, these methods are like any other methods.
They can be static, have different linkages, have their address taken, etc.
)
$(P The built in properties $(D .sizeof), $(D .alignof), and $(D .mangleof)
may not be declared as fields or methods in structs, unions, classes or enums.
)
$(P If a property function has no parameters, it works as a getter.
If has exactly one parameter, it works as a setter.
)
$(H2 $(LNAME2 virtual-functions, Virtual Functions))
$(P Virtual functions are class member functions that are called indirectly through a
function pointer table, called a `vtbl[]`, rather than directly.
Member functions that are virtual can be overridden in a derived class:
)
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
------
class A
{
void foo(int x) {}
}
class B : A
{
override void foo(int x) {}
//override void foo() {} // error, no foo() in A
}
void test()
{
A a = new B();
a.foo(1); // calls B.foo(int)
}
------
)
$(P The `override` attribute is required when overriding a function.
This is useful for catching errors when a base class's member function
has its parameters changed, and all derived classes need to have
their overriding functions updated.)
$(P The $(LNAME2 final, `final`) method attribute
prevents a subclass from overriding the method.)
$(P The following are not virtual:)
$(UL
$(LI Struct and union member functions)
$(LI `final` member functions)
$(LI $(DDSUBLINK spec/attribute, static, `static`) member functions)
$(LI Member functions which are $(D private) or $(D package))
$(LI Member template functions)
)
$(P $(B Example:))
------
class A
{
int def() { ... }
final int foo() { ... }
final private int bar() { ... }
private int abc() { ... }
}
class B : A
{
override int def() { ... } // ok, overrides A.def
override int foo() { ... } // error, A.foo is final
int bar() { ... } // ok, A.bar is final private, but not virtual
int abc() { ... } // ok, A.abc is not virtual, B.abc is virtual
}
void test()
{
A a = new B;
a.def(); // calls B.def
a.foo(); // calls A.foo
a.bar(); // calls A.bar
a.abc(); // calls A.abc
}
------
$(P Member functions with `Objective-C` linkage are virtual even if marked
with `final` or `static`, and can be overridden.
)
$(H3 $(LNAME2 covariance, Covariance))
$(P An overriding function may be covariant with the overridden function.
A covariant function has a type that is implicitly convertible to the
type of the overridden function.
)
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
------
class A { }
class B : A { }
class Foo
{
A test() { return null; }
}
class Bar : Foo
{
// overrides and is covariant with Foo.test()
override B test() { return null; }
}
------
)
$(H3 $(LNAME2 base-methods, Calling Base Class Methods))
$(P To directly call a member function of a base class `Base`,
write `Base.` before the function name.
This avoids dynamic dispatch through a function pointer. For
example:
)
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
------
class B
{
int foo() { return 1; }
}
class C : B
{
override int foo() { return 2; }
void test()