File: CPointerInteropLanguageModel.rst

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (205 lines) | stat: -rw-r--r-- 7,773 bytes parent folder | download
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
:orphan:

We have a pretty good user model for C pointer interop now, but the language
model still needs improvement. Building the user model on top of implicit
conversions has a number of undesirable side effects. We end up with a mess of
pointer types--the intended user-facing, one-word pointer types
``UnsafeMutablePointer`` and ``OpaquePointer``, which expose a full pointer-ish API
and are naturally ABI-compatible with C pointers; and the bridging pointer
types, ``ObjCMutablePointer``, ``CMutablePointer``, ``CConstPointer``,
``CMutableVoidPointer``, and ``CConstVoidPointer``, which have no real API yet
but exist only to carry an owner reference and be implicitly convertible, and
rely on compiler magic to be passed to C functions. Since we can do the magic
pointer bridging only in limited places, we assault users writing method
overrides and reading synthesized headers with both sets of pointer types in a
confusing jumble.

The best solution to this is to burn the user model into the language, giving
function applications special powers to provide the user model for pointers. We
then provide only one set of plain pointer types, with
special intrinsic behavior when used as function arguments.

The Pointer Types
=================

In the standard library, we provide three pointer types:

- ``UnsafePointer<T>``, corresponding to ``T const *`` in C and ARC,
- ``UnsafeMutablePointer<T>``, corresponding to ``T *`` in C, and ``T* __strong *`` in
  ARC for class types, and
- ``AutoreleasingUnsafeMutablePointer<T>`` (for all ``T: AnyObject``), corresponding
  to ``T* __autoreleasing *`` in ARC.

These types are all one word, have no ownership semantics, and share a common
interface. ``UnsafePointer`` does not expose operations for storing to the
referenced memory. ``UnsafeMutablePointer`` and ``AutoreleasingUnsafeMutablePointer`` differ
in store behavior: ``UnsafeMutablePointer`` assumes that the pointed-to reference has
ownership semantics, so ``ptr.initialize(x)`` consumes a reference to ``x``,
and ``ptr.assign(x)`` releases the originally stored value before storing the
new value.  ``AutoreleasingUnsafeMutablePointer`` assumes that the pointed-to
reference does not have ownership semantics, so values are autoreleased before
being stored by either initialize() or assign(), and no release is done on
reassignment. Loading from any of the three kinds of pointer does a strong
load, so there is no need for a separate ``AutoreleasingUnsafePointer``.

Conversion behavior for pointer arguments
=========================================

The user model for pointer arguments becomes an inherent capability of function applications. The rules are:

UnsafeMutablePointer<T>
-----------------------

When a function is declared as taking an ``UnsafeMutablePointer<T>`` argument, it can
accept any of the following:

- ``nil``, which is passed as a null pointer,
- an ``UnsafeMutablePointer<T>`` value, which is passed verbatim,
- an inout expression whose operand is a stored lvalue of type ``T``, which is
  passed as the address of the lvalue, or
- an inout ``Array<T>`` value, which is passed as a pointer to the start of the
  array, and lifetime-extended for the duration of the callee.

As a special case, when a function is declared as taking an
``UnsafeMutableRawPointer`` argument, it can accept the same operands as
``UnsafeMutablePointer<T>`` for any type T.

So if you have a function declared::

  func foo(_ x: UnsafeMutablePointer<Float>)

You can call it as any of::

  var x: Float = 0.0
  var p: UnsafeMutablePointer<Float> = nil
  var a: [Float] = [1.0, 2.0, 3.0]
  foo(nil)
  foo(p)
  foo(&x)
  foo(&a)

And if you have a function declared::

  func bar(_ x: UnsafeMutableRawPointer)

You can call it as any of::

  var x: Float = 0.0, y: Int = 0
  var p: UnsafeMutablePointer<Float> = nil, q: UnsafeMutablePointer<Int> = nil
  var a: [Float] = [1.0, 2.0, 3.0], b: Int = [1, 2, 3]
  bar(nil)
  bar(p)
  bar(q)
  bar(&x)
  bar(&y)
  bar(&a)
  bar(&b)

AutoreleasingUnsafeMutablePointer<T>
------------------------------------

When a function is declared as taking an ``AutoreleasingUnsafeMutablePointer<T>``, it
can accept any of the following:

- nil, which is passed as a null pointer,
- an ``AutoreleasingUnsafeMutablePointer<T>`` value, which is passed verbatim, or
- an inout expression, whose operand is primitive-copied to a temporary
  nonowning buffer. The address of that buffer is passed to the callee, and on
  return, the value in the buffer is loaded, retained, and reassigned into the
  operand.

Note that the above list does not include arrays, since implicit autoreleasing-to-strong writeback of an entire array would probably not be desirable.

So if you have a function declared::

  func bas(_ x: AutoreleasingUnsafeMutablePointer<NSBas?>)

You can call it as any of::

  var x: NSBas?
  var p: AutoreleasingUnsafeMutablePointer<NSBas?> = nil
  bas(nil)
  bas(p)
  bas(&x)

UnsafePointer<T>
---------------------

When a function is declared as taking an ``UnsafeMutablePointer<T>`` argument, it can
accept any of the following:

- nil, which is passed as a null pointer,
- an ``UnsafeMutablePointer<T>``, ``UnsafePointer<T>``, or
  ``AutoreleasingUnsafeMutablePointer<T>`` value, which is converted to
  ``UnsafePointer<T>`` if necessary and passed verbatim,
- an inout expression whose operand is an lvalue of type ``T``, which is passed
  as the address of (the potentially temporary writeback buffer of) the lvalue,
  or
- an ``Array<T>`` value, which is passed as a pointer to the start of the
  array, and lifetime-extended for the duration of the callee.

As a special case, when a function is declared as taking an
``UnsafeRawPointer`` argument, it can accept the same operands as
``UnsafePointer<T>`` for any type ``T``. Pointers to certain integer
types can furthermore interoperate with strings; see `Strings`_ below.

So if you have a function declared::

  func zim(_ x: UnsafePointer<Float>)

You can call it as any of::

  var x: Float = 0.0
  var p: UnsafePointer<Float> = nil
  zim(nil)
  zim(p)
  zim(&x)
  zim([1.0, 2.0, 3.0])

And if you have a function declared::

  func zang(_ x: UnsafeRawPointer)

You can call it as any of::

  var x: Float = 0.0, y: Int = 0
  var p: UnsafePointer<Float> = nil, q: UnsafePointer<Int> = nil
  zang(nil)
  zang(p)
  zang(q)
  zang(&x)
  zang(&y)
  let doubles = [1.0, 2.0, 3.0]
  let ints = [1, 2, 3]
  zang(doubles)
  zang(ints)

A type checker limitation prevents array literals from being passed directly
to ``UnsafeRawPointer`` arguments without type annotation. As a
workaround, you can bind the array literal to a constant, as above, or
specify the array type with ``as``::

  zang([1.0, 2.0, 3.0] as [Double])
  zang([1, 2, 3] as [Int])

This limitation is tracked as <rdar://problem/17444930>.

Strings
=======

Pointers to the following C integer and character types can interoperate with
Swift ``String`` values and string literals:

- ``CChar``, ``CSignedChar``, and ``CUnsignedChar``, which interoperate with
  ``String`` as a UTF-8 code unit array;
- (not implemented yet) ``CShort``, ``CUnsignedShort``, and ``CChar16``, which interoperate with
  ``String`` as a UTF-16 code unit array; and
- (not implemented yet) ``CInt``, ``CUnsignedInt``, ``CWideChar``, and ``CChar32``, which interoperate
  with ``String`` as a UTF-32 code unit array.

A ``UnsafePointer`` parameter with any of the above element types may take
a ``String`` value as an argument. The string is transcoded to a null-terminated
buffer of the appropriate encoding, if necessary, and a pointer to the buffer
is passed to the function.  The callee may not mutate through the array, and
the referenced memory is only guaranteed to live for the duration of the call.