-
Notifications
You must be signed in to change notification settings - Fork 6
/
mf_dt_capture.sthlp
180 lines (130 loc) · 5.4 KB
/
mf_dt_capture.sthlp
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
{smcl}
{* 26mar2014}{...}
{cmd:help mata dt_capture()}
{hline}
{title:Title}
{p 4 4 2}
{bf:dt_capture() {hline 2}} Capture function errors in Mata
{title:Syntax}
{p 8 20 2}
{it:real scalar}
{cmd:dt_capture(}{it:func_ptr}{cmd:,} {it:arg_ptrs} [{cmd:,} {it:rv_ptr}]{cmd:)}
{p 8 20 2}
{it:real scalar}
{cmd:dt_method_capture(}{it:class_name}{cmd:,} {it:func_name}{cmd:,} {it:arg_ptrs} [{cmd:,} {it:rv_ptr}]{cmd:)}
{p 4 8 2}
where
{p 8 12 2}
{it:func_ptr} is a pointer to a function (i.e., a {it:pointer(function) scalar})
{p 8 12 2}
{it:class_name} is a {it:string scalar}
{it:func_name} is a {it:string scalar}
{p 8 12 2}
{p 8 12 2}
{it:arg_ptrs} is a vector containing pointers to the intended arguments, or a zero-dimensional matrix if the function takes no arguments
{p 8 12 2}
{it:rv_ptr} (optional) is a pointer to a pre-defined variable that will hold the return value of the function if it doesn't abort with error
{title:Description}
{pstd}
{cmd:dt_capture()} runs the specified function with the specified arguments. If the
function aborts with error, {cmd:dt_capture()} returns the error code. If the
function does not abort with error, {cmd:dt_capture()} returns zero, and puts the
return value of the function in {it:rv_ptr}, if specified.
{pstd}
{cmd:dt_method_capture()} does the same for a class method.
{title:Examples}
{pstd}
{cmd:dt_capture()} is useful in the same situations as the Stata command
{cmd:capture}. That is, when you want to verify that an error is raised,
or when you want to handle an error yourself (or ignore it) rather than
let the error halt your program.
{p 4 4 2}
{bf:Example 1}
{p 8 8 8}
Suppose you've made a function that tries to add any two inputs and return their
sum.
function add(a, b)
{
return(a + b)
}
{p 8 8 8}
Suppose your larger goal is to return the sum when possible or return the "."
missing value otherwise. You could write a function like this
function any_add(a, b)
{
real scalar rc
transmorphic rv
rc = dt_capture(&add(), (&a, &b), &rv)
if (rc) {
return(.)
}
return(rv)
}
{p 8 8 8}
Your function then can be used like
: any_add(1, 2)
3
: any_add(1, (0, 1))
.
: any_add(" foo ", " bar ")
foo bar
: any_add(" foo ", 2)
.
{p 4 4 2}
{bf:Example 2}
{p 8 8 8}
Suppose you've made a function that takes a single argument which
is allowed to be a vector or zero-dimensional matrix, and suppose you want
an error raised when that condition is not met. There is no built-in Mata
designation for "vector or zero-dimensional matrix", so the input will have
to be checked with custom code.
function thin(a)
{
if (rows(a) > 1 & cols(a) > 1) {
exit(_error(3200, "arg should be vector or zero-dim matrix"))
}
}
{p 8 8 8}
Since an error is being raised manually, you should probably write some tests
to check that the function raises the error you expect exactly when you expect
it to. This can be done with {cmd:dt_capture()} and the built-in {cmd:assert()}.
Some tests you might write:
assert( dt_capture(&thin(), &J(10, 1, 1)) == 0 )
assert( dt_capture(&thin(), &J(0, 0, 1)) == 0 )
assert( dt_capture(&thin(), &J(0, 10, 1)) == 0 )
assert( dt_capture(&thin(), &J(10, 2, 1)) == 3200 )
assert( dt_capture(&thin(), &J(10, 10, 1)) == 3200 )
{title:Conformability}
{cmd:dt_capture(}{it:func_ptr}{cmd:,} {it:arg_ptrs} [{cmd:,} {it:rv_ptr}]{cmd:)}:
{it:func_ptr}: 1 {it:x} 1
{it:arg_ptrs}: 1 {it:x c} or {it:r x} 1 or zero-dimensional
{it:rv_ptr}: 1 {it:x} 1
{it:result}: 1 {it:x} 1.
{cmd:dt_method_capture(}{it:class_name}{cmd:,} {it:func_name}{cmd:,} {it:arg_ptrs} [{cmd:,} {it:rv_ptr}]{cmd:)}:
{it:class_name}: 1 {it:x} 1
{it:func_name}: 1 {it:x} 1
{it:arg_ptrs}: 1 {it:x c} or {it:r x} 1 or zero-dimensional
{it:rv_ptr}: 1 {it:x} 1
{it:result}: 1 {it:x} 1.
{title:Diagnostics}
{p 4 8 8}
{cmd:dt_capture(}{it:func_ptr}{cmd:,} {it:arg_ptrs} [{cmd:,} {it:rv_ptr}]{cmd:)} aborts
with error if {break}
{it:func_ptr} is not a pointer to a function,{break}
{it:arg_ptrs} is not a vector of pointers, or{break}
{it:rv_ptr} (if used) is not a pointer scalar.
{p 4 8 8}
{cmd:dt_method_capture(}{it:class_name}{cmd:,} {it:func_name}{cmd:,} {it:arg_ptrs} [{cmd:,} {it:rv_ptr}]{cmd:)} aborts with error if{break}
{it:class_name} is not a string scalar,{break}
{it:func_name} is not a string scalar,{break}
{it:arg_ptrs} is not a vector of pointers, or{break}
{it:rv_ptr} (if used) is not a pointer scalar.
{p 4 4 8}
{cmd:dt_method_capture()} will return 3000 if there is no class with name
{it:class_name} or the class has no function with name {it:func_name}.
{pstd}
{cmd:dt_method_capture()} will not work with classes defined within a function.
{title:Author}
{pstd}
James Fiedler{break}
{browse "mailto:[email protected]":[email protected]}