SE-0289: Function Builders

Just as concrete types like ViewBuilder or ShortcutBuilder refer to the single value produced by the builder, @returnValueBuilder refers to the single return value, not to the intermediary steps.

I had proposed @returnValueBuilder thinking of the Swift principle of clarity over brevity. I believe it is more precise than either @valueBuilder or @returnBuilder.

I believe all builders, whether associated with this feature or not, build a value of some kind so @valueBuilder does not seem any more descriptive to me than just @builder, which I think is too general a name for the attribute.

I also agree with @Jon_Shier that @returnBuilder on its own doesn't make too much sense, since there's no real precedent for 'return' to be used as a noun. (Although admittedly it is less of a mouthful / eyeful.)

I personally had rejected @resultBuilder as a name because the term 'result' is very general.

However, I had forgotten about @discardableResult which provides precedent in the language of using 'result' as a synonym for 'returnValue'.

The section on Type Methods in The Swift Programming Language describes the connection plainly:

“Because it’s not necessarily a mistake for code that calls the advance(to:) method to ignore the return value, this function is marked with the @discardableResult attribute.”

The grammar also defines function-result and subscript-result as the parts of function and subscript declarations that declare the type of the return value.

Since there is already precedence for using the term 'result' to mean 'return value', I've changed my opinion about @resultBuilder and think it would also work well as a name.

For me the pros and cons for @resultBuilder as opposed to @returnValueBuilder are:

Pros:

  • Consistency with the naming of @discardableResult
  • Further establishes 'result' as a synonym for 'return value' in the language
  • A more concise name without losing precision
    (at least, precision in the context of how 'result' is formally used in the language).

Cons:

  • It's not immediately evident that 'result' means 'return value' and could be confused with any expression result.
    (On the other hand one could interpret the name 'result builder' as building not only the the final return value, but also building the result of each statement, which is also accurate.).
  • The connection within the diagnostic messages mentioned by @beccadax would be less direct.

I think that both @returnValueBuilder and @resultBuilder are suitable names, and I hope one of them is chosen.

My own personal preference now leans towards @resultBuilder because of the consistency with the existing usage of 'result' and because I believe it reads / writes / sounds better without losing clarity.

6 Likes

Thank you for the explanation. The additional example in the proposal clarifies things a great deal.

1 Like

I enjoyed this thread on naming.

My favorites are @resultBuilder for the reasons discussed in the thread and the simple @builder. Either are general terms which are specialized to what is actually being created: @ViewBuilder, @SlideBuilder, @BikeShedBuilder.

As to the rest of the proposal, I've been using @_functionBuilders since they were available and love the power they offer for simplifying APIs. I am not expert enough to understand many of the objections but hope that smarter people will adjust the proposal in accordance to those that will have impact.

I really appreciate the work and thought put into the proposal and the review. I think this is going to be a big deal.

2 Likes

Yep, I have the same feeling.

Result actually is return value, and @resultBuilder also comply with @*Builder pattern - to build * through partial results and make them into the final result.

We are NOT building any functions, right? We just using @_functionBuilder attribute to build statement results through/by a set of static functions. Function is the tool what we use to build something what we want, but not the result we want to build. So @resultBuilder is what the result what we want to build - build statement results.

3 Likes

Does anyone actually have another builder incarnation in mind that precludes using plain old @builder as the attribute name, or is avoiding that purely a theoretical future-proofing? I find the various arguments for @resultBuilder as the name compelling, if @builder is off the table for being too broad.

2 Likes

(First, sorry for the deleted messages, I had meant this post to reply directly and got all fouled up trying to fix it.)

For me, it's less about any specific future language feature and more that the Builder design pattern is already widely used in Swift code in contexts outside of this feature.

Doing a quick search on GitHub for Swift source files with the term 'builder' but excluding the term '_functionBuilder' shows over 54,000 source files using the term. (The number varies per search for some reason. 54K+ was the low number, 80K+ was the high number)

This includes types like PathBuilder, AttributedStringBuilder, AdvertisementsBuilder, MerchantRequestBuilder.

I haven't done a comprehensive, file by file inspection, but the name and concept of 'builder' is already in widespread use in Swift code beyond the usage of this feature, and I would imagine builders that don't use this feature will continue to be created by Swift developers.

2 Likes

To add on to this, a search for "swift builder" on Google turns up lots of articles about using the builder design pattern in Swift. Choosing the @builder name would, in the best case, hide these otherwise relevant results. In the worst case, it would make searching for information about the @builder attribute quite difficult. OTOH, searching for "swift result builder" or "swift return value builder" already returns results that almost exclusively discuss "function builders." I don't get the sense that choosing either of these names would 'step on the toes' of existing concepts.

An interesting middle ground is searching for "swift value builder", which returns results which (at least for myself) are approximately 50/50 split between "function builders" and "builder design pattern." I worry that this is the realm we would end up in if we chose a name like @builder.

FWIW, I support the @resultBuilder or @returnValueBuilder namings over the alternatives in this thread (including @functionBuilder) with no strong preference between the two.

2 Likes

I don't agree with this last statement. Conceptually, a given declaration can satisfy the requirements from more than one protocol. In practice, it's just one almost all of the time, and "Jump to Protocol Requirement" will have a single destination. One can handle multiple destinations in a UI in a straightforward manner.

I'm not quite sure what you're looking for here. I wrote some clarifications to buildEither and buildOptional in this clarification PR. Does that align with your suggestion?

Doug

Yeah, I actually reread it and was about to bring it up in that response (and forgot to do so). So the current design have 4 scenarios?

  • No Optional or Either: No branching allowed,
  • Optional only: Only if without else allowed,
  • Either only: Only exhaustive if-else and switch allowed,
  • Both Optional and Either: All if-else and switch allowed.

If so, yes, it does align. Thank you for your patience.

4 Likes

They're discussed a little bit in Future Directions. This virtualized form is fairly different from the design of this feature today. It needs to be a separate thing.

I think we can consider that ship to have sailed, yes.

Doug

1 Like

Yes.

Doug

2 Likes

:thinking::thinking:. That would be true. I suppose my worried is more about whether the IDEs will catch up.

So far they haven't. For instance @dynamicMemberLookup has no links to the definition of the feature, no fix its for the requires, and no autocomplete for the required methods, even in Xcode 12. Perhaps the addition of a far more complex attribute in @*Builder will help prioritize these features.

1 Like

While I don't disagree that the authoring experience could certainly be better (and will be: see below), the bar we've generally set for the evolution process is that the feature can be implemented to provide a good user experience, and the implementation provided is suitable to get a feel for the feature and demonstrate its implementability. I think this proposal clears that bar handily.

You are applying a much more stringent standard on the quality of implementation here. While perhaps that's fine when the proposal authors are core team members and technical leads on the compiler, I would not want this to be the standard to which we hold every proposal. The implementation-required bar is high already, and raising it further in this regard seems unfair to the proposers, especially when some of the requests (e.g., regarding Xcode's behavior) could not possibly be met by anyone outside of Apple.

That's the meta-point. To the point about function builders specifically, yes, they could be better. I've implemented improved code completion and Fix-Its to guide function builder type authors. To save everyone a click, here's what it does:

  • When the function builder transformation cannot be applied because of a missing build method, e.g., because the body uses if-else but the function builder doesn't provide buildEither(first:) and buildEither(second:), add a note + Fix-It to the error message that adds stubs for the functions needed to support those statements. Same for missing buildBlock on a @_functionBuilder type.

  • When code-completing with the definition of a function builder type, provide a full set of completions for all of the build functions that function builders support, along with brief documentation comments stating what each does.

  • Add an educational note outlining the builder functions that a function builder can provide.

    Doug

25 Likes

As to the naming...

Like naming libdispatch "Grand Central Dispatch", I think this should be named:

@magicBuilder

As omochimetaru describes, this is really entering a meta-language, and out-of-Swift experience. Like Author C. Clarke said:

Any sufficiently advanced technology is indistinguishable from magic.

When reading Swift code, when you enter a part marked with @magicBuilder you should not only be prepared for something like custom operators, but a completely different mindset. Like magic. It's a builder using some kind of magic compared to the standard Swift rules.

5 Likes

metaBuilder

1 Like

@magicBuilder sounds like a great name. It's consistent with the UnsafePointer style naming. Where the words Unsafe or Magic act as warnings.

2 Likes

@magicFunctionBuilder at a minimum (IMO), it needs to be clear that this is magic happening within a function context, lest more 'magic' is added in the future. I'm in full agreement that this needs to be very clear this is not a 'normal' feature in Swift.

I am not sure if that would be a good name. Besides, we already have places where “magic” happens, like synthesised conformances, but we don’t use the word “magic” in such contexts. For example, we have a protocol called “Codable” and not “MagicCodable”.

3 Likes

It's amazing to me how much of this review process has been devoted to bikeshedding the property wrapper name.

That is all. Carry on.

2 Likes