SE-0289 (review #2): Result Builders

What I meant was that in the context of a function there is only one result and it is returned at the end of the function. But here the result we are building is actually a partial transformation of an argument for the function to make better sense of it.
But if this is not obvious, probably ArgumentInterpreter is not that good of a naming after all. :man_shrugging:

The issue I have with @resultBuilder is that it's unspecific—in a way every constructor or collection literal can be described as building a result.

To me, the most significant feature that is introduced by SE-0289 is not that it allows to write builders that produce results—that was possible before. It's the way how components of builder results are captured—by collecting values that would be ignored under normal semantics.

My preferred name for the attribute would therefore be @valueCollector. It describes concisely what is provided by the feature additionally to normal code execution (collection of unused values). The actual building is done in specific implementations (HTMLBuilder, TupleBuilder, etc). For those types the "Builder" suffix works very well, but I think for the feature that enables these kinds of builders the name @valueCollector works better as a disambiguation from other kinds of builders.

12 Likes

This isn't a very strong argument considering how quickly the language moves, along with the community. People get used to the changes (e.g. compactMap), and old versions are buried in history as they should. I think we shouldn't limit ourselves for a short term learnability impact if it means a more unclear and confusing set of names in the long term (which I believe is one of the roots of what makes a "bad" language bad).

4 Likes

Everything you can build in Swift is a "result," so "result builder" isn't any better from "data builder" or "value builder." You might as well just go with "builder." And since anything that computes a value can be considered a builder of that value, you really have very little semantic information in this name.

Function builder wasn't great, but it had the advantage of making some reference to a quality that would distinguish this builder from any other component that might build something such as a factory class.

Anyway, the problem with this name comes from the fact that we've chosen to try to qualify the word "builder," which naturally leads to the qualification being interpreted as "what gets built.“ But "building something" is not what distinguishes this feature.

IMO this feature distinguishes itself by collecting the results of expression-statements, so it would be better called something like "expression-collector."

Note: I hadn't seen @lassejansen's post when I posted this; you could think of my idea as a refinement of what they wrote. The idea of “collecting” is important, but I think “value” leaves a bit to be desired as it is still unspecific, since everything is a value.

18 Likes

Like many of the other more general names suggested, this is too abstract to be useful. Most developers won't know what it means to collect expressions, and nobody wanting to build a DSL in Swift will think of this name when looking into how to do so.

2 Likes

We can add support for the instance versions later if we find they are needed. This isn't a now-or-never decision. That's one of the big advantages of ad hoc protocols.

Personally, I've moved from a "don't care" on making these instance methods to thinking it's the wrong answer. Result builders already have a way to capture all of the results--that's what they do, and they feed the results into the various build functions along the way, with buildFinalResult providing a way to turn those into a single result value. If we put result builder instances into the mix, now there are two ways to track the partial results. As far as I can tell, instance methods don't add any expressivity, so why invent another way to track state?

To your specific comments:

What would this look like? Do all of your build functions return some sentinel value because all of the state is in the builder? To me, that would be more confusing--different result builders would take very different forms based on where the state goes.

This is a separable concern. There's no reason we can't do this with the static methods.

Doug

2 Likes

FWIW, I consider James Dempsey's analysis on why we should keep the "Builder" suffix to outweigh any incremental improvements from alternative suffixes like "composer" or "collector".

Doug

You and I must have very different understandings of "general" and "abstract"

I don't understand how you could say that "expression-collector" is a "more general" name. The point was to focus on the things that make this feature different from other things in the language. If anything, that makes it a more specific, concrete name.

What could possibly be more abstract than "result builder?" It could mean anything. Every single function or method in the whole language is a "result builder."

Nobody wanting to build a DSL in Swift will think of "result builder" when looking into how to do so any more than they'd think of "value producer." They are essentially equivalent names, neither of which means anything more than "this is a function."

Aside from our disagreements about what these words mean, I disagree with you about what matters in naming this feature.

It doesn't matter at all that most developers don't know what it means to collect expressions. Most developers don't know about this feature. If you explain the feature as collecting the values of expression-statements in a function body, they will have a great way to understand and remember the name, and to conceptualize what you can, and can't, do with it.

7 Likes

To Dave's point here, nobody is saying that "result builder" doesn't describe what this feature does. We are just saying that it is too generic (and also describes every function and computed property). We have several words to be more specific (which would exclude describing every function and computed property), so why not use them?

Afaict the main reason I'm seeing as push-back to selecting a more specific word is that all of the concrete types implemented with the pre-release @_functionBuilder use "Builder"...this is also mentioned in James Dempsey's analysis as reasoning for sticking with the "builder" suffix. It's unfortunate that people were able to latch on to the "builder" suffix before the feature's release, and that that is now being used as a reason to not select a more specific suffix.

3 Likes

But it collects the result of expressions, not the expression themselves. And only when the result would normally be discarded (it does not collect the result when assigned to a variable). It'd be more precise to call it a @discardedResultCollector.

But then this feature is not only about collecting results: the builder can map and restrict the control flow. So then @discartedResultControlFlowCollector? Perhaps a bit too long.

@resultFlowCollector sounds better.

Or @resultFlowBuilder if we want to keep "builder" in the name.

The only way to describe a result builder in a way that disambiguates it from a hundred other things we already do is to describe the mechanism by which it does what it does, and naming something after the 'how' is often pretty bad from a communication point of view. As someone who's comically unqualified to have a credible opinion on this, it all feels like another symptom of ResultBuilders sitting awkwardly between being a feature of the language or of a framework.

1 Like

If you want to be pedantic about it, that's true, which is why I put the hyphen in the name. In other words, it's a collector driven by expressions. But I think most people aren't as pedantic as you and I, and don't distinguish expressions from their values, and won't read the hyphen as meaningful, so they'll see it as a collector of expressions, which is close enough to accurate.

Well, but the results aren't discarded, are they? They get collected.

I am perhaps not familiar with that part of the proposal. I doubt it's practical, though, to try to capture every aspect of this feature in its name. IMO capturing the primary aspect of the feature is

Sorry, the possible meaning of "result flow" is lost on me.

@flowCoder

It will encode the possible flows of the statements in a given block, and build some useful value from it.

I disagree. Currently, "result builder" describes every function and computed property.

Arguably, "result composer" implies that the result is made up of components (Admittedly, it is unclear whether "builder" implies a result made up of components or not, personally I don't think it does). Not every function and computed property's result is made up of components. Therefore, "result composer" still describes the feature, but does not describe every function and computed property, which means "result composer" is less ambiguous.

when swift ui (@_functionBuilder) is being used, is the usage of that in swift ui expressions or statements?

if im creating expressions in swift ui via the dsl, doesnt it make more sense to call it expressionBuilder ?

maybe this feature doesnt directly create expressions, but it allows the usage of them in place of statemnents and describes more or what this thing is for i think...

am i wrong about that?

1 Like

IMHO, for the naming we should think about to things sharply:

  1. What is it specifically? (a builder, a mapper, a controller or a composer or whatever)
  2. What does it create? (results, functions, components, statements, values …)

Combine both of them and you got a good name.

"Builder" and "composer" are largely synonymous in this context, so your argument applies to both. However, I disagree with your characterization that functions and computed properties are builders. That's kind of like saying every human is a builder, since every person could be building at some point. Additionally, while compose and component may have the same root, they aren't strictly related in English. You don't compose something out of components, you compose it out of whatever describes the constituent parts of the composition. And compose isn't generally used like that anyway. In any case there's nothing more specific about "composer", so sticking with the more familiar "builder" seems appropriate.

1 Like

What about the part where it applies custom logic to turns the collected expression-results into a final value? If “collector” described it, wouldn’t it produce a collection? But it doesn’t; it produces a value, or put another way, a result. It ‘builds’ the result out of the collected expression-results. That’s why @resultBuilder seems so particularly accurate, at least to me.

Ok, assuming this is true and the general consensus is that composer and builder are synonymous in this context, then I am fine with builder. Maybe it's just my local version of English that thinks composer and builder are not equivalent.

By "more general" I mean that it both lacks meaning to most developers (i.e. is nebulous unless you're familiar with the very specific meaning of the phrase already) and describes the feature only at the highest level. Whereas "resultBuilder" has a more concrete meaning to most developers (even if it's not precise) and describes the feature in specific terms reflected in the API. Besides which, isn't "collector" rather misleading? Most developers would expect something that collects things to produce a collection of some kind at the end.

I mean, isn't this feature supposed to allow a new way of creating such a result? It sounds like you've rediscovered the logic for the original name. Of course, since it doesn't actually provide a new way to create functions but instead the result of the function, this rename was suggested.

True, no one thinking DSL will think of a specific attribute name that doesn't have DSL in the name. And having DSL in the name doesn't really help anyone else. In truth I think you've (accidentally) produced a pretty good argument for resultBuilder: it's a combination of special syntax and API that exposes a limited version of the what the compiler does in a function to produce a value.

If it doesn't matter that most developers don't know what it means to collect expressions, how is your explanation of the feature valuable? Also, isn't your summary here incomplete? The feature doesn't just collect the values of expression statements in a function body, it uses them to produce a value (or result) like @michelf pointed out. So that's what the developer of the builder is really doing, and that's what the user of the feature sees. So the collection of expression statements seems more like an implementation detail than the feature itself. To put it another way, if this feature could be implemented differently, it would still make sense to call it a "result builder" but not an "expression-collector". To me that suggests @resultBuilder is the more applicable name.

Ultimately I suppose the question is this: is this feature more about the collection of expressions in a special function syntax or the results produced from that collection?