Merge branch 'master' of ctdb into 'master' of samba
[samba.git] / ctdb / lib / talloc / doc / tutorial_dts.dox
1 /**
2 @page libtalloc_dts Chapter 3: Dynamic type system
3
4 @section dts Dynamic type system
5
6 Generic programming in the C language is very difficult. There is no inheritance
7 nor templates known from object oriented languages. There is no dynamic type
8 system. Therefore, generic programming in this language is usually done by
9 type-casting a variable to <code>void*</code> and transferring it through
10 a generic function to a specialized callback as illustrated on the next listing.
11
12 @code
13 void generic_function(callback_fn cb, void *pvt)
14 {
15   /* do some stuff and call the callback */
16   cb(pvt);
17 }
18
19 void specific_callback(void *pvt)
20 {
21   struct specific_struct *data;
22   data = (struct specific_struct*)pvt;
23   /* ... */
24 }
25
26 void specific_function()
27 {
28   struct specific_struct data;
29   generic_function(callback, &data);
30 }
31 @endcode
32
33 Unfortunately, the type information is lost as a result of this type cast. The
34 compiler cannot check the type during the compilation nor are we able to do it
35 at runtime. Providing an invalid data type to the callback will result in
36 unexpected behaviour (not necessarily a crash) of the application. This mistake
37 is usually hard to detect because it is not the first thing which comes the
38 mind.
39
40 As we already know, every talloc context contains a name. This name is available
41 at any time and it can be used to determine the type of a context even if we
42 lose the type of a variable.
43
44 Although the name of the context can be set to any arbitrary string, the best
45 way of using it to simulate the dynamic type system is to set it directly to the
46 type of the variable.
47
48 It is recommended to use one of talloc() and talloc_array() (or its
49 variants) to create the context as they set its name to the name of the
50 given type automatically.
51
52 If we have a context with such as a name, we can use two similar functions that
53 do both the type check and the type cast for us:
54
55 - talloc_get_type()
56 - talloc_get_type_abort()
57
58 @section dts-examples Examples
59
60 The following example will show how generic programming with talloc is handled -
61 if we provide invalid data to the callback, the program will be aborted. This
62 is a sufficient reaction for such an error in most applications.
63
64 @code
65 void foo_callback(void *pvt)
66 {
67   struct foo *data = talloc_get_type_abort(pvt, struct foo);
68   /* ... */
69 }
70
71 int do_foo()
72 {
73   struct foo *data = talloc_zero(NULL, struct foo);
74   /* ... */
75   return generic_function(foo_callback, data);
76 }
77 @endcode
78
79 But what if we are creating a service application that should be running for the
80 uptime of a server, we may want to abort the application during the development
81 process (to make sure the error is not overlooked) and try to recover from the
82 error in the customer release. This can be achieved by creating a custom abort
83 function with a conditional build.
84
85 @code
86 void my_abort(const char *reason)
87 {
88   fprintf(stderr, "talloc abort: %s\n", reason);
89 #ifdef ABORT_ON_TYPE_MISMATCH
90   abort();
91 #endif
92 }
93 @endcode
94
95 The usage of talloc_get_type_abort() would be then:
96
97 @code
98 talloc_set_abort_fn(my_abort);
99
100 TALLOC_CTX *ctx = talloc_new(NULL);
101 char *str = talloc_get_type_abort(ctx, char);
102 if (str == NULL) {
103   /* recovery code */
104 }
105 /* talloc abort: ../src/main.c:25: Type mismatch:
106    name[talloc_new: ../src/main.c:24] expected[char] */
107 @endcode
108
109 */