[swift-dev] `withUnsafePointer` mutates `self`

Ryan Lovelett swift-dev at ryan.lovelett.me
Wed Dec 16 08:59:20 CST 2015


On Wed, Dec 16, 2015, at 03:12 AM, Dave Abrahams via swift-dev wrote:
> 
> > On Dec 15, 2015, at 11:51 PM, Kevin Ballard <kevin at sb.org> wrote:
> > 
> > On Tue, Dec 15, 2015, at 11:25 PM, Dave Abrahams wrote:
> >> 
> >>> On Dec 15, 2015, at 6:46 PM, Kevin Ballard <kevin at sb.org> wrote:
> >>> 
> >>> On Tue, Dec 15, 2015, at 06:39 PM, Dave Abrahams wrote:
> >>>> 
> >>>>> On Dec 15, 2015, at 6:33 PM, Kevin Ballard via swift-dev <swift-dev at swift.org> wrote:
> >>>>> 
> >>>>> On Tue, Dec 15, 2015, at 03:03 PM, Joe Groff via swift-dev wrote:
> >>>>>> 
> >>>>>> Yeah, it seems to me like a reasonable refinement for 'withUnsafePointer' to take an immutable parameter. Since this is a stdlib API change, you should suggest that on swift-evolution.
> >>>>> 
> >>>>> A change like that is going to break any code that relies on the inout optimization (where it uses call-by-reference instead of copy-in copy-out when possible). Yes, such code is in violation of Swift semantics today, but it does work.
> >>>> 
> >>>> Two questions:
> >>>> 
> >>>> 1. Don’t we want a withUnsafeMutablePointer for the mutating cases (where the inout optimization can take effect) anyway?
> >>> 
> >>> I'm thinking here of cases like passing a context pointer to KVO. You're not actually mutating it, you just need a pointer that's the same every time you call the code.
> >> 
> >> Well, it is not possible to code a version of withUnsafePointer that makes that guarantee in Swift.
> > 
> > Yeah but we want to move in the direction of making that more reliable, not less.
> 
> I am not sure I agree with you.  I would defer to John McCall on this
> one, but my understanding is that it's an explicit non-goal to make that
> guarantee.
> 
> > I forget who but someone said in another thread that global variables can be reliably passed by-ref to functions that take pointers already (even though the Swift documentation does not guarantee this).
> > 
> > Come to think of it, what's the actual use-case for withUnsafePointer()?
> 
> I'm not sure we still have one that isn't covered by &x; that's my point.
> 
> > If a value is mutable, you can already use &x or withUnsafeMutablePointer(), and if it's immutable, you can't call withUnsafePointer() today anyway. The proposed change would just make withUnsafePointer() into the equivalent of `var x = value; callSomethingWith(&x)`. The only reason to really want a withUnsafePointer() function is if it can give you an UnsafePointer to an immutable value without copying it, but we can't do that. I'm inclined to say we should just get rid of withUnsafePointer() entirely, at least until such time as Swift has a way to pass immutable values by-ref.
> 
> I'm inclined to agree.  Proposal?

This line of thinking is hard for me to wrap my head around. I _get_
that in my original example I could have easily changed the code to be:

func profileName(profile: Int32) -> String? {
  var mutatingSelf = self
  let result = av_get_profile_name(&mutatingSelf, profile)
  return String.fromCString(result)
}

Now the self reference is still constant, thus no `mutating` keyword on
the func definition. From that stand point alone I suppose problem
solved.

I also get that Swift uses some sort of
copy-on-write/copy-on-modifcation for these sorts of cases therefore
there is not a significant performance overhead in the `var mutatingSelf
= self` because `av_get_profile_name` takes a `const AVCodec *` or
`UnsafePointer<AVCodec>` and thus is guaranteed to _not_ modify
mutatingSelf; thus saving the copy.

The thing that is hard for me to wrap my head around: how is any of that
obvious to the developer? I was always under the impression that one of
Swift's goals was to help a developer write clear and concise code. This
line of thinking at least partially feels like the opposite of that.
>From my perspective, taking away `withUnsafePointer` we are actively
walking in the other direction of clear. Though I concede this might be
_slightly_ more concise. However, trading conciseness for clarity seems
like a bad idea.

A thought experiment that I went through when thinking about this
proposal was assume that `withUnsafeMutablePointer` or
`withUnsafePointer` had _never_ been in the Swift language. The proposed
code above still would not feel idiomatic to me. The code above
explicitly makes a mutable copy of self so that it can send it to a
function that guarantees it will not mutate it. 😕

It feels like a hack/work-around for a limitation of the language.
Effectively this syntax says that Swift, by design, is asymmetric when
it comes to pointers. The language can _injest_ your C `const` params or
non-`const` params idiomatically but will not provide an idiomatic
method to send them back. Feels wrong.

All that having been said. I get that `const` and non-`const` are just
compiler abstractions but so are `var` and `let`. Furthermore, one or
more of my assumptions might be completely wrong and I am by no means a
language expert. Like I said at the start I don't want to make a fool of
myself. I already feel like I'm wading into neck deep water and might be
in over my head here shortly. My comments are meant to be from the
perspective of someone who knows nothing about how the Swift compiler
works; just how I'd _expect_ it to work as a consumer of the compiler.

> _______________________________________________
> swift-dev mailing list
> swift-dev at swift.org
> https://lists.swift.org/mailman/listinfo/swift-dev


More information about the swift-dev mailing list