Hi Jordan.

Thanks for the lengthy answer.

> On Mar 1, 2017, at 6:21 PM, Jordan Rose <jordan_r...@apple.com> wrote:
> 
> Hey, Kenny. The const vs non-const part is important, since both the implicit 
> conversion and cString(using:) are allowed to return a pointer to the 
> internal data being used by the String, and modifying that would be breaking 
> the rules (and could potentially cause a crash). In the case of 'fieldSep', 
> it's unlikely that anyone is going to mutate the contents of the string; it 
> was probably just the original author (you?) not bothering to be 
> const-correct. If you control this struct, a better fix would be to use 
> 'const char *' for the field.

This is the PostgreSQL client library, so I don’t really want to change it. 
(Although the source is available. Maybe I should submit a patch…)

> That said, that's not the main isuse. The implicit conversion from String to 
> UnsafePointer<CChar> is only valid when the string is used as a function 
> argument, because the conversion might need to allocate temporary storage. In 
> that case, it’s important to know when it’s safe to deallocate that storage. 
> For a function call, that’s when the call returns, but for storing into a 
> struct field it’s completely unbounded. So there’s no implicit conversion 
> there.
> 
> If you’re willing to limit your use of the pointer value to a single block of 
> code, you can use withCString 
> <https://developer.apple.com/reference/swift/string/1538904-withcstring>:
> 
> myString.withCString {
>   var opt :PQprintOpt = PQprintOpt()
>   opt.fieldSep = UnsafeMutablePointer(mutating: $0)
>   // use 'opt'
> }

Unfortunately, this is not always an option, since there are multiple char * 
files in PQprintOpt. Or could I just nest .withCString calls? Looks ugly, but 
might work, I guess.

> Note that it is illegal to persist the pointer value beyond the execution of 
> withCString, because it might point to a temporary buffer.
> 
> Alternately, if you’re willing to call free() later, you can use the C 
> function strdup:
> 
> opt.fieldSep = strdup(myString)
> // use ‘opt’
> free(opt.fieldSep)
> 
> 
> Of course, all of this is overkill for a string literal. Perhaps when Swift 
> gets conditional conformances, we could consider making UnsafePointer<CChar> 
> conform to ExpressibleByStringLiteral. Meanwhile, you can use the type 
> designed specifically for this purpose, StaticString 
> <https://developer.apple.com/reference/swift/staticstring>:
> 
> let separator: StaticString = “|”
> opt.fieldSep = UnsafeMutablePointer(mutating: separator.utf8start)
> 
> Note that you still have to do the init(mutating:) workaround for the fact 
> that you’re not allowed to mutate this string.

Ah - that's 

>> 
>> Also, why is the conversion to Swift an IUO? NULL is a totally valid value 
>> for fieldSep.
> 
> You're welcome to mark that field as _Nullable on the C side, but without 
> annotations Swift makes very few assumptions about pointers imported from C.

If it’s “making very few assumptions”, I would think that, for safety’s sake, 
functions that return a pointer would always be optional, forcing the user to 
deal with any possible null pointer returns.

> Hope that helps!

Definitely!

-Kenny




_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Reply via email to