Update Swift.org API guidelines regarding "get" in function names

Apple has this old set of guidelines for naming methods in Cocoa APIs. In the Accessor Methods section of this guideline, it is stated:

If the property is expressed as a noun, the format is:
- ( type ) noun ;
- (void)set Noun : ( type ) aNoun ;

Specifically it is stated regarding the use of "get" in method names:

Use “get” only for methods that return objects and values indirectly. You should use this form for methods only when multiple items need to be returned.
- (void)getLineDash:(float *)pattern count:(int *)count phase:(float *)phase;
In methods such as these, the implementation should accept NULL for these in–out parameters as an indication that the caller is not interested in one or more of the returned values.

Apple seems to follow these guidelines in all its current Swift APIs, yet the official Swift.org API design guidelines are conspicuously silent regarding when it might be appropriate to use "get" in a function name.

I believe this omission was likely due to the fact property accessors have special syntax in Swift:

var foo: Int {
    get { ... }
    set { ... }
} 

However, out in the wild I keep seeing functions that violate the old Cocoa standards, like:

func getFoo(for bar: Bar) { ... }
func setFoo(for bar: Bar) { ... }

Of course this leads to inconsistency between Swift APIs written by those who still follow the Cocoa guidelines (including Apple) and newer Swift devs who may be coming over from languages where it's normal to have "get" in function names.

I think this current situation is a direct consequence of the fact that our Swift API guidelines do not explicitly say not to use "get" for functions that return a value.

So my pitch is that we should update the Swift.org API design guidelines with the same basic guidelines about the use of "get" in method names as was found in the Cocoa guidelines:

If a property is accessed or set through a function, the format is:
func noun() -> Type
func setNoun(label: Type)

Use “get” only for methods that return objects and values indirectly (as with inout or pointer parameters). You should use this form for methods only when multiple items need to be returned, e.g.:

func getLineDash(_ pattern: UnsafeMutablePointer<CGFloat>?, count: UnsafeMutablePointer<Int>?, phase: UnsafeMutablePointer<CGFloat>?)

Thoughts?

3 Likes

While I agree with the post, the fact that you see such things, you can also find a lot of StackOverflow samples where people from C# background use capital letters to name their properties (var Foo: Int, func DoSomething()) and I would assume that the get/set-prefixed functions is mainly used by developers that come from Java background.

The question is if it is of any interest to such developers to even read the guidelines.

It is IMHO a pity that Xcode still does not have a configurable embedded linter (there were some talks about this about 2 years ago?), turned on by default. Then a lot of these things could be picked up and the developer could be learning on the go.

From what I've seen, when you develop in several languages on daily basis and you're not entirely a code-style-freak (meant in a good way), you find a middle ground that works for you and apply it across all projects.

Many of these violations "in the wild" are due to the standards of other languages being applied to Swift get / set pairings are common in Java and C#, so those developers tend to use the same naming in Swift. We can see this a lot in libraries like SwiftNIO, especially the earlier versions, which ported much of a Java library to Swift.

Personally I really dislike get (and to a lesser extent set) as part of method names. There are almost always better terms for the action performed by a method. For your example, getLineDash should likely be something like parseLineDash or extractLineDash.

1 Like

The example being discussed is based on an actual method in NSBezierPath. It really isn't parsing or extracting anything; it's just retrieving a C-style array (expressed as pointer-to-start + count) and a related value, and returning them indirectly because that's the best way to express such an API in Objective-C.

A more idiomatic Swift declaration for this API might look like:

public var lineDash: (
  pattern: [CGFloat], // maybe UnsafeBufferPointer if copy hurts
  phase: CGFloat
) { get set }

In lieu of that dramatically different bridging, I can't think of a better name than getLineDash(_:count:phase:).

1 Like

Its extracting concrete values from the buffers, no?

I do agree that bridging ties Swift's hands here and there isn't really a great way around it.

This is one of my pet peeves also.

I think it probably needs more explanation though.

Simple properties are just var or let and of course don't have get in their names. Why would one want to 'access a property' through a function when it can be a simple var or let? Computed properties.

I think people often think about computed properties differently from simple Ints and Strings, and this contributes to the use of get. This is a particular cocoa pod that I've used, from the wild, that has several get methods: YPDrawSignatureView/YPDrawSignatureView.swift at master · GJNilsen/YPDrawSignatureView · GitHub

public func getSignature(scale:CGFloat = 1) -> UIImage? { ... }

public func getCroppedSignature(scale:CGFloat = 1) -> UIImage? { ... }

public func getPDFSignature() -> Data { ... }

My thought is that the author doesn't think of these functions as properties. They think of this functionality as functions that do some work and return a value. The work is constrained to the function itself but there's not a simple type that is hanging around to be returned. In the case of a network request that fetches data from a server most people wouldn't think of that as a simple property, even if it could be written as a computed property.

If I had written that signature view I would have probably made those three methods as methods, not properties, but I would not have used get in the method names. So

public func signature(scale:CGFloat = 1) -> UIImage? { ... }

public func croppedSignature(scale:CGFloat = 1) -> UIImage? { ... }

public func pdfSignature() -> Data { ... }

For network transactions I usually use fetch in the names, like fetchData or similar.

The Java developers use get a lot but also other verbs like build, calculate and others to make their method names have two or more parts. get is the default verb but lots of others are used as well. I had a Java dev like that on one of my projects. I fixed all the bad names after they left.

The Cocoa description you show comes from the old days before Obj-C 2.0 and @properties when you had to write your own getters and setters. I'm not sure that your setFoo() really exists. It's definitely ```get`` that's the problem.

I'm definitely in favor of adding this to the API guidelines.

2 Likes

I'm sure you're right, especially since Java tends to be what gets taught at a college level.

Well... all the developers that I work with are full-time iOS devs who try their best to follow the Swift coding standards—and generally they do a great job of it.

However without any guideline to the contrary, people fall back on the patterns they learned from Java in college.

And on a PR review if you say, "Might be better to leave off get," and they say, "Why?" ... then it would be nice to be able to point to the official guidelines for Swift rather than referring to archived, Objective C Cocoa API guidelines :smiley: (Doing that just makes me feel like a dinosaur. Haha)

2 Likes

I completely agree with you. Fetch works, but I think "get" is fine when it's asynchronous web request where the HTTP method is actually GET (as opposed to POST or PUT etc.).

Maybe a better form of the new rule could be:

Avoid prefixing function names with “get"; instead, use the noun form of what is being returned in the function name. The exception to this is when, instead of directly returning a value, a method sets the value of an inout or pointer parameter, or performs an asynchronous data fetch (like HTTP GET). E.g.:

func getLineDash(_ pattern: UnsafeMutablePointer<CGFloat>?, count: UnsafeMutablePointer<Int>?, phase: UnsafeMutablePointer<CGFloat>?)

If you look at all the properties in UIView and the rest of UIKit they have names that are simple nouns, like: frame, bounds, isHidden etc. If it were Java they would be getFrame(), getBounds(), getIsHidden() etc. Now these are properties not methods but the point is to think about this kind of method as if it's a simple property so its name is a noun like other properties.

It's almost certain that some of the properties in classes like CGRect are computed properties rather than simple properties. But their names are all simple nouns anyway.

I have long felt this way about methods prefixed with on, like onAppear, but I appear to have lost that battle. :grinning:

1 Like

There’s a semantic difference between appear and onAppear as appear sounds like a verb indicating the actor should “make an appearance” while onAppear makes it clear that something should trigger when the appearance happens. I’m curious how you support your position.

It’s a matter of taste, I just don’t like them.

2 Likes
  1. get is not necessary for functions, but it is for closures, because Swift closures don't have argument labels, and a closure has to be differentiated from what it returns.

e.g.

func thing() -> Thing …
let getThing = thing

// new scope where a `self.` can't help us:
let thing = getThing()
  1. set can be necessary as a prefix because Swift does't have named set-only subscripts.

See here for several use cases for that missing feature:
https://developer.apple.com/documentation/metal/mtlcomputecommandencoder

e.g. textures[0] = texture instead of this: Apple Developer Documentation

  1. Method names beginning with prepositions (e.g. onAppear) are incorrect because they neither describe the action of a method nor its return value. A correctly-named imperative method (not using DSL syntax) requires one of those to be true.

Good point. This should be mentioned as an exception to the rule also. Including this we would have:

Use of "get" in Function Names
Avoid prefixing function names with “get"—instead, use the noun form of what is being returned in the function name.

There are three kinds of exception to this:

  • when a function sets the value of an inout or pointer parameter instead of directly returning a value, e.g.:
    func getLineDash(_ pattern: UnsafeMutablePointer<CGFloat>?, count: UnsafeMutablePointer<Int>?, phase: UnsafeMutablePointer<CGFloat>?)
  • when a function gets something asynchronously, especially if it uses HTTP GET to do so, e.g.:
    func get(request: URLRequest, completion: @escaping (URLResponse) -> Void )
  • when a function that returns something is stored as a closure property, e.g.:
    func thing() -> Thing …
    let getThing = thing

I believe this is because these APIs were all created originally in Objective C using the Cocoa API Design Guidelines that I linked above. And of course they carried over into Swift. I like it being this way. Just think it would be best to make it an explicit guideline, since right now it's a bit of a tribal knowledge thing.