How do I create an UnsafePointer<X> variable (not parameter)?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

How do I create an UnsafePointer<X> variable (not parameter)?

Jens Alfke
Given a variable of type X, how do I create an UnsafePointer<X> variable that points to it? This doesn’t work:

typealias X = UInt32
var x: X = 1234
var p: UnsafePointer<X> = &x

The compiler complains “‘&’ used with non-inout argument” and helpfully offers to remove the “&”, which of course just makes things worse.

The closest I’ve come is:

var p = UnsafePointer<X>(&x)

which fails with “ambiguous use of ‘init’”. The problem is that UnsafePointer has an init that takes UnsafePointer and another that takes UnsafeMutablePointer, and “&x” could be converted to either of those.
But if I try to disambiguate like this:

var p = UnsafePointer<X>(&x as UnsafePointer<X>)

then the compiler again complains  “‘&’ used with non-inout argument” :-p

Why am I doing this? Because I’m calling a C function that takes a parameter of type "const X*”, and I need to either pass the address of an X variable, or nil, depending on some condition. That means I need to pre-create an UnsafePointer<X> that will either point to the variable or be nil, and pass that to the function.

—Jens

PS: I’m using Xcode 7.1 on El Capitan.

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/AED15BD2-47E5-4C00-B80D-3CE5C398AA29%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: How do I create an UnsafePointer<X> variable (not parameter)?

Ken Ferry
On Nov 5, 2015, at 2:04 PM, Jens Alfke <[hidden email]> wrote:

Given a variable of type X, how do I create an UnsafePointer<X> variable that points to it? This doesn’t work:

typealias X = UInt32
var x: X = 1234
var p: UnsafePointer<X> = &x

The compiler complains “‘&’ used with non-inout argument” and helpfully offers to remove the “&”, which of course just makes things worse.

The closest I’ve come is:

var p = UnsafePointer<X>(&x)

which fails with “ambiguous use of ‘init’”. The problem is that UnsafePointer has an init that takes UnsafePointer and another that takes UnsafeMutablePointer, and “&x” could be converted to either of those.
But if I try to disambiguate like this:

var p = UnsafePointer<X>(&x as UnsafePointer<X>)

then the compiler again complains  “‘&’ used with non-inout argument” :-p

Why am I doing this? Because I’m calling a C function that takes a parameter of type "const X*”, and I need to either pass the address of an X variable, or nil, depending on some condition. That means I need to pre-create an UnsafePointer<X> that will either point to the variable or be nil, and pass that to the function.

For this purpose you should be able to pass &x directly to the function. 



Constant Pointers

When a function is declared as taking a UnsafePointer<Type> argument, it can accept any of the following:

  • nil, which is passed as a null pointer.
  • An UnsafePointer<Type>UnsafeMutablePointer<Type>, or AutoreleasingUnsafeMutablePointer<Type> value, which is converted to UnsafePointer<Type> if necessary.
  • String value, if Type is Int8 or UInt8. The string will automatically be converted to UTF8 in a buffer that lasts for the duration of the call.
  • An inout expression whose left-hand side operand is of type Type, which is passed as the address of the left-hand side identifier.
  • [Type] value, which is passed as a pointer to the start of the array, and lifetime-extended for the duration of the call.

If you have declared a function like this one:

  1. func takesAPointer(x: UnsafePointer<Float>) {
  2. // ...
  3. }

You can call it in any of the following ways:

  1. var x: Float = 0.0
  2. var p: UnsafePointer<Float> = nil
  3. takesAPointer(nil)
  4. takesAPointer(p)
  5. takesAPointer(&x)
  6. takesAPointer([1.0, 2.0, 3.0])


Somewhat more generally,

/// Invokes `body` with an `UnsafePointer` to `arg` and returns the
/// result. Useful for calling Objective-C APIs that take "in/out"
/// parameters (and default-constructible "out" parameters) by pointer.
public func withUnsafePointer<T, Result>(inout arg: T, @noescape _ body: UnsafePointer<T> throws -> Result) rethrows -> Result

and for non-structs:

/// Returns an `UnsafePointer` to the storage used for `object`.  There's
/// not much you can do with this other than use it to identify the
/// object.
@warn_unused_result
public func unsafeAddressOf(object: AnyObject) -> UnsafePointer<Void>

-ken

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/CC1A1E4B-9C01-4B1A-8375-998BE8ED14DA%40gmail.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: How do I create an UnsafePointer<X> variable (not parameter)?

Jens Alfke
In reply to this post by Jens Alfke
I did figure out a way to do it, but it’s a silly kludge:

func unsafify(x: UnsafePointer<X>) -> UnsafePointer<X> {
    return x
}

var p: UnsafePointer<X> = nil
if (x > 100) { // some silly condition
    p = unsafify(&x)
}

This seems to point [sic] to a hole in the language — the conversion from X to UnsafePointer<X> is only available as part of parameter-passing, so here I have to artificially go through a no-op function call to invoke it.

—Jens

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/55E45AF0-1AA5-4AB4-ACC4-071A981F1607%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: How do I create an UnsafePointer<X> variable (not parameter)?

Jens Alfke
In reply to this post by Ken Ferry

On Nov 5, 2015, at 2:13 PM, Ken Ferry <[hidden email]> wrote:

For this purpose you should be able to pass &x directly to the function. 

Yup, and that’s what I’ve been doing in other places in my code. However in this place I need to pass either &x or nil, depending on circumstances. And that led to a lot of pain.

—Jens

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/6D51BBB3-035D-421D-A32C-6C15B6135591%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: How do I create an UnsafePointer<X> variable (not parameter)?

Adam Sharp
In reply to this post by Jens Alfke
I think the withUnsafePointer() family of functions is probably more what you're after. The pointer is then lexically scoped to the closure that you pass. If you need to allocate memory on the heap, you can use UnsafePointer<T>.alloc() and copy the memory from the pointer you get via withUnsafePointer().

On Nov 06, 2015, at 09:24 AM, Jens Alfke <[hidden email]> wrote:

I did figure out a way to do it, but it’s a silly kludge:

func unsafify(x: UnsafePointer<X>) -> UnsafePointer<X> {
    return x
}

var p: UnsafePointer<X> = nil
if (x > 100) { // some silly condition
    p = unsafify(&x)
}

This seems to point [sic] to a hole in the language — the conversion from X to UnsafePointer<X> is only available as part of parameter-passing, so here I have to artificially go through a no-op function call to invoke it.

—Jens

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/d34582f3-cc00-4121-a06d-232ae546f2d5%40me.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: How do I create an UnsafePointer<X> variable (not parameter)?

Kevin Ballard
In reply to this post by Jens Alfke
That's not just a kludge; it's actually fundamentally unsafe. Swift's inout parameters follow a writeback semantic model; for every call to a function with an inout parameter, it behaves as though it makes a local copy of the value, passes a pointer to that to the function, and then when the function returns it writes the local copy back to the original location. Swift does have an optimization where if you pass a reference to a memory location (e.g. variable or stored property), it will actually just pass the pointer to that location in to the function instead of doing a literal writeback, but you're not supposed to rely on this optimization. As long as you don't rely on this optimization, you can convert a stored property to a computed property without breaking any code.
 
Because of that, constructing an UnsafePointer<X> like you're doing is fundamentally unsafe; you're holding onto a pointer value past the scope where the pointer is valid.
 
There exists functions called withUnsafePointer() and withUnsafeMutablePointer() (and variants of these) that give you a pointer to a value that's valid for a nested scope. That's the supported way of working with pointers, but holding onto the pointer after the scope is over is a violation of the language semantics.
 
As a side note, these same semantics are why the OSAtomic family of functions are technically unsafe to call from Swift (because the atomic operations they perform might actually be occurring on local copies and not on the original memory location) and everyone who does so is relying on the aforementioned optimization.
 
-Kevin Ballard
 
On Thu, Nov 5, 2015, at 02:24 PM, Jens Alfke wrote:
I did figure out a way to do it, but it’s a silly kludge:
 
func unsafify(x: UnsafePointer<X>) -> UnsafePointer<X> {
return x
}
 
var p: UnsafePointer<X> = nil
if (x > 100) { // some silly condition
p = unsafify(&x)
}
 
This seems to point [sic] to a hole in the language — the conversion from X to UnsafePointer<X> is only available as part of parameter-passing, so here I have to artificially go through a no-op function call to invoke it.
 
—Jens


--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
 

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/1446762859.1074095.430487641.38506402%40webmail.messagingengine.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: How do I create an UnsafePointer<X> variable (not parameter)?

Kevin Ballard
In reply to this post by Adam Sharp
If you're allocating on the heap with UnsafePointer<T>.alloc() then withUnsafePointer() is entirely superfluous, because calling `withUnsafePointer(&ptr.memory)` is just going to end up creating the exact same value that `ptr` already represents (after optimization; technically according to the semantics of the language it may give you a pointer to a temporary copy of `ptr.memory`, but in practice it will just give you `ptr`).
 
-Kevin
 
On Thu, Nov 5, 2015, at 02:28 PM, Adam Sharp wrote:
I think the withUnsafePointer() family of functions is probably more what you're after. The pointer is then lexically scoped to the closure that you pass. If you need to allocate memory on the heap, you can use UnsafePointer<T>.alloc() and copy the memory from the pointer you get via withUnsafePointer().
 
On Nov 06, 2015, at 09:24 AM, Jens Alfke <[hidden email]> wrote:
I did figure out a way to do it, but it’s a silly kludge:
 
func unsafify(x: UnsafePointer<X>) -> UnsafePointer<X> {
return x
}
 
var p: UnsafePointer<X> = nil
if (x > 100) { // some silly condition
p = unsafify(&x)
}
 
This seems to point [sic] to a hole in the language — the conversion from X to UnsafePointer<X> is only available as part of parameter-passing, so here I have to artificially go through a no-op function call to invoke it.
 
—Jens


--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
 

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/1446762969.1074355.430492729.1663AC00%40webmail.messagingengine.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: How do I create an UnsafePointer<X> variable (not parameter)?

Jens Alfke
In reply to this post by Kevin Ballard

On Nov 5, 2015, at 2:34 PM, Kevin Ballard <[hidden email]> wrote:

Because of that, constructing an UnsafePointer<X> like you're doing is fundamentally unsafe; you're holding onto a pointer value past the scope where the pointer is valid.

You’re right; I’d forgotten about that bit. 

There exists functions called withUnsafePointer() and withUnsafeMutablePointer() (and variants of these) that give you a pointer to a value that's valid for a nested scope. That's the supported way of working with pointers

Supported, but not well-documented o_O
The “Swift And Objective-C” book only describes how to pass a value to an UnsafePointer parameter, not how to do anything else with pointers.
I did dig through the API docs, but assumed I’d find the answer in the UnsafePointer API … I didn’t think of looking through all the global functions. Thanks for revealing the answer!

—Jens

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/D471C69B-583B-4190-A434-530243FE2B6F%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.