Swift Pointer Syntatic Sugar

I propose to add synaptic sugar for creating pointers. This involves use of the *.

Reason:
Swift provides a handy way to create optionals. This involves the use of T? rather then Optional<T> However, when creating pointers, things can be especially verbose.

Solution:
There should be syntactic sugar for an UnsafeMutablePointer<T>, where T is from the declaration T*.

Similar to optionals, this should not affect readability because it is unlikely that you will have many *s. At most you will have 2 if you want to split text by some delimiter.

4 Likes

Do you have any use cases for this? I can't think of any.

2 Likes

Are you suggesting T* be syntactic sugar for UnsafeMutablePointer<T>? Because your implementation displays a new operator retrieving the pointer for a value (Side note: Your implementation allocates a new pointer rather than actually point to the value passed. I don't know if that's what you were going for. This also leaves the deallocation up to the caller.)

1 Like

I would like to reference this particular post in regard to the topic:

I am often working with UnsafeMutablePointer<Bytecode> and this hurts readability. Rather we can just have this: Bytecode*

Also, if you want to split cStrings you end up with UnsafeMutablePointer<UnsafeMutablePointer<CChar>> rather than CChar**

While I think sugar for unsafe pointers is unlikely to get much traction in the short term, I do agree that it is an interesting topic for discussion. C is arguably a domain-specific language for twiddling pointers unsafely; almost every other language fails to match the concision of C in this regard.

I do think that a broader view is needed here however. A shorthand for UnsafeMutablePointer might be nice for some cases, but what about UnsafePointer and UnsafeBufferPointer? It is not clear that privileging one pointer type over the others is the right approach. Also, seeing the word "Unsafe" appear in code is a big red flag that the reader should proceed carefully; a single * obscures the fact that unsafe things are happening and arguably makes it too "easy" to do the wrong thing.

There are also various operations on pointers that might benefit from sugar. We should also think about how this interacts with any future borrow checking or ownership features as well.

6 Likes

shorthand for UnsafeMutablePointer might be nice for some cases, but what about UnsafePointer and UnsafeBufferPointer?

I never use UnsafePointer or the buffer variant. Why would you even use the buffer variants?

a single * obscures the fact that unsafe things are happening and arguably makes it too "easy" to do the wrong thing.

Maybe provide a dismissible compiler warning?

In addition to Slava's points, I would also add that the vast majority of Swift code doesn't use unsafe pointers. That code can currently use prefix * as a custom operator for whatever purpose their codebase would benefit from.

If your particular codebase uses pointers very heavily, you can always abbreviate the pointer type's name with typealias Ptr<T> = UnsafeMutablePointer<T>; then your code can use Ptr<Bytecode>. You could even abbreviate it to P<Bytecode> if Ptr is too long.

5 Likes

We considered having type sugar for the unsafe pointer types back before Swift 1.0 and intentionally decided against it. I'm not saying that we can never reconsider that decision, but I personally still feel we made the right decision.

12 Likes

If your particular codebase uses pointers very heavily, you can always abbreviate the pointer type's name with typealias Ptr<T> = UnsafeMutablePointer<T> ; then your code can use Ptr<Bytecode> . You could even abbreviate it to P<Bytecode> if Ptr is too long.

But thank of a developer. They want to split a c string by new lines.

They see Ptr<Ptr<CChar>>. This is not a Swifty way of doing things

I guess this is closed now

The buffer variants manage their storage; you can allocate space for one or more elements and free it. The raw variants don't have an element type; just a blob of bytes. Both are useful in addition to the basic UnsafePointer and UnsafeMutablePointer variants.

One approach is to add a new "unsafe" block or function annotation and only allow the sugar to be used within that scope. These are all fine ideas to discuss, but it merits more design than just adding a simple sugar for an existing type constructor.

I would suggest the developer convert the C string to a Swift String and split it with standard library or Foundation APIs. This way you get memory safety and correct behavior with non-ASCII characters.

I would really not want to do anything to make it easier to call libc string APIs from Swift. There are many legitimate uses for unsafe pointers; this isn't it :)

9 Likes

How to close topic?

I can close it for you if you really want. We don't usually close threads, though.

Oh, Ok

Right. I think we have the correct design here. It is important that you can express unsafe constructs in Swift, but equally important that it is clear in the code that this is happening. Unsafe being visible is a useful thing.

-Chris

12 Likes

Kinda out of the blue here, but would it be possible to make the shorthand type definitions extendable?
As in some way to define in code that T? := Optional<T>, [T] := Array<T> and [K: V] := Dictionary<K, V>.
If that were possible (under considerate grammar restrictions) then this whole topic can become just an utility that would be added ad-hoc for projects that do deal a lot with different wrapper types, as UnsafeMutablePointer<T> in this case.

2 Likes

I added a #withdrawn tag to the thread as a visual marker for readers. This also mimics how some previous proposals were withdrawn by their authors. It would be cool if the community would use this tag more often on ideas that are abandoned similar to how we mark topics with #off-topic that are unrelated to this forum.

1 Like

Ok

I like this idea. The problem with this approach is that people can abuse it. Also, the compiler must know what things have been made so that stdlib shorthand's are not redefined.

Instead of := maybe this:

shorthand T* = UnsafeMutablePointer<T>

But a problem arises when things like ? Is defined by this:

Int*?

Is this UnsafeMutablePointer<Int?> or UnsafeMutablePointer<Int>?